Sqlite3 GROUPBY with HAVING and ORDER BY not working - sqlite

I have a SQL query that is calculating the correct output, and is even doing the order by correctly, however it is not executing the having clause. am i doing something wrong? It is not filtering the percentages at all.
select table1.name as theme,
printf("%.2f", cast(count(table2.name)as float)/(select count(table2.name)
from table1
join table2
where table1.id = table2.theme_id)*100) as percentage from table1
join table2
where table1.id = table2.theme_id
group by table1.id
having percentage >=5.00
order by percentage desc;

The problem is that since printf() returns a string, the calculated column percentage is a string and you compare it to 5.00 which is a number.
This comparison can't give you what you expect because it is not a comparison between numbers.
One way to solve this is to drop printf() and use round() which returns a number instead:
select table1.name as theme,
round(cast(count(table2.name)as float)/(select count(table2.name)
from table1
join table2
where table1.id = table2.theme_id)*100, 2) as percentage from table1
join table2
where table1.id = table2.theme_id
group by table1.id
having percentage >=5.00
order by percentage desc;
or cast percentage to float:
having cast(percentage as float) >= 5.00

Related

SQLite 3 - Return multiple SELECT with JOIN results to one row

I have 5 SELECTs with a JOIN in each that individually return the data I'm querying without any issue. They are:
SELECT table1.typeName FROM table1 JOIN table6 ON table1.OwnerID = table6.OwnerID;
SELECT table2.typeName FROM table2 JOIN table6 ON table2.typeID = table6.typeID;
SELECT table3.itemName FROM table3 JOIN table6 ON table3.itemID = table6.moonID;
SELECT table4.name FROM table4 JOIN table6 ON table4.state = table6.state;
SELECT Timestamp FROM table6;
What I have been trying to do is take all of these SELECTs and return all the data on one row.
The closest thing I tried was a subquery? that went like this:
SELECT
(SELECT table1.typeName FROM table1 JOIN table6 ON table1.OwnerID = table6.OwnerID),
(SELECT table2.typeName FROM table2 JOIN table6 ON table2.typeID = table6.typeID),
(SELECT table3.itemName FROM table3 JOIN table6 ON table3.itemID = table6.moonID),
(SELECT table4.name FROM table4 JOIN table6 ON table4.state = table6.state),
(SELECT Timestamp FROM table6);
It worked, but it only returned the first row. So I tried doing UNION ALL with them. It worked, but it would return all the data sequentially.
Some columns in table6 have duplicate data and some columns don't.
Is there any way I can return the data on one row?
EDIT: #Makoto. I'll go a few more steps back.
We have data from a server that dumps data into columns on table6 of the database. The data in the columns are numeric/alphanumeric code and don't mean anything to the end user.
Now, the other tables have columns with the same numeric/alphanumeric codes AND another column with a description.
So, I want to select columns on table6, have it look up the descriptions on the other tables and return the descriptions, like (based on the information in table6)
typeName|typeName|itemName|name|Timestamp
Once the data gets returned like that, I can use Python to create a readable message that is automatically sent to a feed.
Based on my limited knowledge, I thought that something like the SELECT with JOIN commands I put together would achieve this goal, but I can't figure it out. I suspect I'm going down the wrong path.

Getting median of column values in each group

I have a table containing user_id, movie_id, rating. These are all INT, and ratings range from 1-5.
I want to get the median rating and group it by user_id, but I'm having some trouble doing this.
My code at the moment is:
SELECT AVG(rating)
FROM (SELECT rating
FROM movie_data
ORDER BY rating
LIMIT 2 - (SELECT COUNT(*) FROM movie_data) % 2
OFFSET (SELECT (COUNT(*) - 1) / 2
FROM movie_data));
However, this seems to return the median value of all the ratings. How can I group this by user_id, so I can see the median rating per user?
The following gives the required median:
DROP TABLE IF EXISTS movie_data2;
CREATE TEMPORARY TABLE movie_data2 AS
SELECT user_id, rating FROM movie_data order by user_id, rating;
SELECT a.user_id, a.rating FROM (
SELECT user_id, rowid, rating
FROM movie_data2) a JOIN (
SELECT user_id, cast(((min(rowid)+max(rowid))/2) as int) as midrow FROM movie_data2 b
GROUP BY user_id
) c ON a.rowid = c.midrow
;
The logic is straightforward but the code is not beautified. Given encouragement or comments I will improve it. In a nutshell, the trick is to use rowid of SQLite.
This is not easily possible because SQLite does not allow correlated subqueries to refer to outer values in the LIMIT/OFFSET clauses.
Add WHERE clauses for the user_id to all three subqueries, and execute them for each user ID.
SELECT user_id,AVG(rating)
FROM movie_data
GROUP BY user_id
ORDER BY rating

SQL query for finding the first, second and third highest numbers

What is an example query to retrieve the first, second and third largest number from a database table using SQL Server?
You can sort by your value descendingly and take the top 3.
SELECT TOP 3 YourVal FROM YourTable ORDER BY YourVal DESC
Or if you wanted each result separate,
first number :
SELECT TOP 1 YourVal FROM YourTable ORDER BY YourVal DESC
second number:
SELECT TOP 1 YourVal FROM YourTable
WHERE YourVal not in (SELECT TOP 1 YourVal FROM YourTable ORDER BY YourVal DESC)
ORDER BY YourVal DESC
third number:
SELECT TOP 1 YourVal FROM YourTable
WHERE YourVal not in (SELECT TOP 2 YourVal FROM YourTable ORDER BY YourVal DESC)
ORDER BY YourVal DESC
assuming YourVal is unique
EDIT : following on from OPs comment
to get the nth value, select the TOP 1 that isn't in the TOP (n-1), so fifth can be chosen by:
SELECT TOP 1 YourVal FROM YourTable
WHERE YourVal not in (SELECT TOP 4 YourVal FROM YourTable ORDER BY YourVal DESC)
ORDER BY YourVal DESC
The proposed SELECT TOP n ... ORDER BY key will work but you need to be aware of the fact that you might get unexpected results if the column you're sorting on is not unique. Find more information on the topic here.
Sudhakar,
It may be easier to use ROW_NUMBER() or DENSE_RANK() for some of these questions. For example, to find YourVal and other columns from the fifth row in order of YourVal DESC:
WITH TRanked AS (
SELECT *,
ROW_NUMBER() OVER (
ORDER BY YourVal DESC, yourPrimaryKey
) AS rk
)
SELECT YourVal, otherColumns
FROM TRanked
WHERE rk = 5;
If you want all rows with the fifth largest distinct YourVal value, just change ROW_NUMBER() to DENSE_RANK().
One really big advantage to these functions is the fact that you can immediately change a "the nth highest YourVal" query to a "the nth highest YourVal for each otherColumn" query just by adding PARTITION BY otherColumn to the OVER clause.
In certain DBMS packages the top command may not work. Then how to do this? Suppose we need to find the 3rd largest salary in employee table. So we select the distinct salary from the table in descending order:
select distinct salary from employee order by salary desc
Now among the salaries selected we need top 3 salaries, for that we write:
select salary from (select distinct salary from employee order by salary desc) where rownum<=3 order by salary
This gives top 3 salaries in ascending order. This makes the third largest salary to go to first position. Now we have the final task of printing the 3rd largest number.
select salary from (select salary from (select distinct salary from employee order by salary desc) where rownum<=3 order by salary) where rownum=1
This gives the third largest number. For any mistake in the query please let me know. Basically to get the nth largest number we can rewrite the above query as
select salary from (select salary from (select distinct salary from employee order by salary desc) where rownum<=**n** order by salary) where rownum=1
If you have a table called Orders and 3 columns Id, ProductId and Quantity then to retrieve the top 3 highest quantities your query would look like:
SELECT TOP 3 [Id], [ProductId], [Quantity] FROM [Orders] ORDER BY [Quantity] DESC
or if you just want the quantity column:
SELECT TOP 3 [Quantity] FROM [Orders] ORDER BY [Quantity] DESC
This works prefect!
select top 1 * from Employees where EmpId in
(
select top 3 EmpId from Employees order by EmpId
) order by EmpId desc;
If you would like to get 2nd, 3rd or 4th highest just change top3 to appropriate number.

SQLite - sorting question

I am using the following query to display database rows in an alphabetical order:
SELECT word_id FROM table1 ORDER BY word ASC
But I want to get values from table2, where I don't have column "word" and to sort it by column "word" which is in table1.
I want something like this:
SELECT word_id FROM table2 ORDER BY table1.word ASC
Thank you in advance.
You must connect the two tables with a join:
SELECT t2.word_id
FROM table2 t2
, table1 t1
WHERE t2.word_id = t1.word_id -- this is the join
ORDER BY t1.word ASC

How to know if a row doesn't exist?

I have the following query:
SELECT rowid FROM table1 ORDER BY RANDOM() LIMIT 1
And as well I have another table (table3). In that table I have columns table1_id and table2_id. table1_id is a link to a row in table1 and table2_id is a link to a row in another table.
I want in my query to get only those results that are defined in table3. Only those that have table1 rowid in their table1_id column. There may not be any columns at all referring to a certain table1 rowid so in this case I don't want to receive them.
How can I achieve this goal?
Update: I tried the following query, which doesn't work:
SELECT rowid FROM table1
WHERE rowid IN (SELECT table1_id FROM table3 WHERE table1_id = table1.rowid)
ORDER BY RANDOM() LIMIT 1
SELECT rowid FROM table1
WHERE rowid IN ( SELECT DISTINCT table1_id FROM table3 )
ORDER BY RANDOM() LIMIT 1;
This query means "choose at random a row from table1 which has an entry in table3".
Every row in table1 equal likelihood of being selected (DISTINCT) as long as it is referenced at least once in table3.
If you are trying to get more than one result, then you should remove the "ORDER BY RANDOM() LIMIT 1" clause.
Assuming you want to select more than just a rowid, you need to SELECT from a JOIN between the tables you're interested in. SQLite doesn't have the full set of standard JOIN functionality, so you'll need to re-work your query so it can use a LEFT OUTER JOIN.
SELECT table1.rowid, table1.other_field
FROM table3
LEFT OUTER JOIN table1 ON table3.table1_id = table1.rowid
ORDER BY RANDOM()
LIMIT 1;

Resources