Guys i want to get the top 3 disease and also their count from following table for a particular year..what query should i run?
mysql> select id,dname,d_id,entrydate from patient_master;
+----+------------------+------+------------+
| id | dname | d_id | entrydate |
+----+------------------+------+------------+
| 1 | Root Canal | 1 | 2012-08-02 |
| 2 | Cosmetic Filling | 3 | 2012-05-10 |
| 3 | Root Canal | 1 | 2012-05-25 |
| 4 | High BP | 6 | 2012-07-09 |
| 5 | Root Canal | 1 | 2012-07-10 |
| 6 | Normal Filling | 2 | 2012-05-10 |
| 7 | Maleria | 4 | 2012-07-10 |
| 8 | Maleria | 4 | 2012-07-12 |
| 9 | Typhoid | 5 | 2012-07-12 |
+----+------------------+------+------------+
9 rows in set (0.00 sec)
Use a group by clause to combine results by disease, and count(*) to count the number of records for each disease. You can then order from largest to fewest and use limit 3 to get only the top 3. I have also included a where clause to filter for only records in 2012.
select count(*), dname
from patient_master
where entrydate between '2012-01-01' and '2013-01-01'
group by dname
order by count(*) desc
limit 3
Demo: http://www.sqlfiddle.com/#!2/89c06/6
SELECT d_id, dname, count(d_id) as `count`, year(entrydate) as `year`
FROM patient_master
GROUP by `year`, d_id
ORDER BY `year` DESC, `count` DESC
Note I didn't put a limit here, as if you want to get both year and count in the same query, you would need to get into writing a pretty complex query to get the top 3 per year.
This will sort by year descending and then by disease count descending within each year. You will note be able to get the row id in this query, nor should you care about that value given what you are trying to do.
Related
I'm sorry for fuzzy title of this question.
I have 2 Tables in my database and want to count records of first_table using "group by" on a foreign key id that exists in a column of second_table (which stores ids like array "1,2,3,4,5").
id | name | fk_id
1 | john | 1
2 | mike | 1
3 | jane | 2
4 | tailor | 1
5 | jane | 3
6 | tailor | 5
7 | jane | 4
8 | tailor | 5
9 | jane | 5
10 | tailor | 5
id | name | fk_ids | s_fk_id
1 | xxx | 1,5,6 | 1
2 | yyy | 2,3 | 1
3 | zzz | 9 | 1
4 | www | 7,8 | 1
Now i wrote the following query but it not working properly and displays wrong numbers.
I WANT TO:
1-Count records in first_table group by "fk_id"
2-Sum the counted records which exists in "fk_ids"
3-Display the sum result (sum of related counts) grouped by id.
symbol ' ' means ``.
select sum(if(FIND_IN_SET('fk_id', 'fk_ids')>0,'count',0) 'sum', 'count', 'from'.'fk_id', 'second_table'.* FROM 'second_table'
LEFT JOIN
(
SELECT 'fk_id', count(*) 'count'
FROM 'first_table'
group BY 'fk_id'
) AS 'from'
ON FIND_IN_SET('fk_id', 'fk_ids')>0
WHERE 'second_table'.'s_fk_id'=1
GROUP BY 'id'
ORDER by 'count' DESC
This table has many data and we have no plan to change the structure.
Edit:
Desired output:
id | name | sum
1 | xxx | 7 (3+4+0)
2 | yyy | 2 (1+1)
3 | zzz | 0 (0)
4 | www | 0 (0+0)
After two holidays i came back to work and found out that the "FIND_IN_SET" function is not working properly with space contained string.
And the problem is that i was ignored the spaces too, (same as this question)
Finnaly this query worked:
select sum(`count`) `sum`, `count`, `from`.`fk_id`, `second_table`.* FROM `second_table`
LEFT JOIN
(
SELECT `fk_id`, count(*) `count`
FROM `first_table`
group BY `fk_id`
) AS `from`
ON FIND_IN_SET(`fk_id`, replace(`fk_ids`,' ',''))>0
WHERE `second_table`.`s_fk_id`=1
GROUP BY `id`
ORDER by `count` DESC
And the magic is replace(fk_ids,' ','')
I have two tables, one that store product information and one that stores reviews for the products.
I am now trying to get the number of reviews submitted for the products between two dates but for some reason I get the same results regardless of the dates i put.
This is my query:
SELECT
productName,
COUNT(*) as `count`,
avg(rating) as `rating`
FROM `Reviews`
LEFT JOIN `Products` using(`productID`)
WHERE `date` BETWEEN '2015-07-20' AND '2015-07-30'
GROUP BY
`productName`
ORDER BY `count` DESC, `rating` DESC;
This returns:
+------------+---------------------+
| productName| count|rating |
+------------+------+--------------+
| productA | 23 | 4.3333333 |
| productB | 17 | 4.25 |
| productC | 10 | 3.5 |
+------------+---------------------+
Products table:
+---------+-------------+
|productID | productName|
+---------+-------------+
| 1 | productA |
| 2 | productB |
| 3 | productC |
+---------+-------------+
Reviews table
+---------+-----------+--------+---------------------+
|reviewID | productID | rating | date |
+---------+-----------+--------+---------------------+
| 1 | 1 | 4.5 | 2015-07-27 17:47:01|
| 2 | 1 | 3.5 | 2015-07-27 18:54:22|
| 3 | 3 | 2 | 2015-07-28 13:28:37|
| 4 | 1 | 5 | 2015-07-28 18:33:14|
| 5 | 2 | 1.5 | 2015-07-29 11:58:17|
| 6 | 2 | 3.5 | 2015-07-30 15:04:25|
| 7 | 2 | 2.5 | 2015-07-30 18:11:11|
| 8 | 1 | 3 | 2015-07-30 18:26:23|
| 9 | 1 | 3 | 2015-07-30 21:35:05|
| 10 | 1 | 4.5 | 2015-07-31 14:25:47|
| 11 | 3 | 0.5 | 2015-07-31 14:47:48|
+---------+-----------+--------+---------------------+
when I put two random dates that I do know for sure they not on the date column, I will still get the same results. Even when I want to retrieve records only on a certain day, I get the same results.
You should not use left join, because by doing so you retrieve all the data from one table. What you should use is something like :
select
productName,
count(*) as `count`,
avg(rating) as `rating`
from
products p,
reviews r
where
p.productID = r.productID
and `date` between '2015-07-20' and '2015-07-30'
group by productName
order by count desc, rating desc;
If the result, given your sample data, that you're looking for is:
| productName | count | rating |
|-------------|-------|--------|
| productA | 5 | 4 |
| productB | 3 | 3 |
| productC | 1 | 2 |
This is the count and average of reviews made on any date between 2015-07-20 and 2015-07-30 inclusive.
Then the there are two issues with your query. First, you need to change the join to a inner join instead of a left join, but more importantly you need to change the date condition as you are currently excluding reviews that fall on the last date on the range, but after midnight.
This happens because your between clause compares datetime values with date values so the comparison ends up being date between '2015-07-20 00:00:00' and '2015-07-30 00:00:00' which clearly excludes some dates at the end.
The fix is to either change the date condition so that the end is a day later:
where date >= '2015-07-20' and date < '2015-07-31'
or cast the date column to a date value, which will remove the time part:
where date(date) between '2015-07-20' and '2015-07-30'
Sample SQL Fiddle
You are using a LEFT JOIN between your reviews and your products tables. This will result in all the rows of reviews being shown with some rows having all product columns left empty.
You should use INNER JOIN, as this will filter only the wanted results.
(In the end I can only guess, since I don't even know which column belongs to which table ...)
The full query (very similar to Angelo Giannis's solution):
select
productName,
count(*) as `count`,
avg(rating) as `rating`
from
products INNER JOIN reviews USING(productId)
where date between '2015-07-20' and '2015-07-30'
group by productName
order by count desc, rating desc;
Here a fiddle with my and Angelo's solution (they both work).
I have a quiz report table which shows a report for every quiz a user takes. I need to create a leaderboard from this, which shows the top users best score, filtering by points and then time taken.
here is a link to a sql fiddle http://sqlfiddle.com/#!2/65fbf0/1
I am really struggling as i need to filter the results by two columns for one user, my ideal result would be
Results for Quiz id 1
---------------------------------------------------------------
| user_id | points | time_spend | start_dt | quiz_id |
| 1 | 3 | 0.5 | May,15 2015| 1 |
| 2 | 3 | 0.8 | May,15 2015| 1 |
| 3 | 2 | 0.5 | May,15 2015| 1 |
Then a separate query for all quiz's showing the results from the last week
Results from all Quizzs
---------------------------------------------------------------
| user_id | points | time_spend | start_dt | quiz_id |
| 1 | 3 | 0.5 | May,15 2015| 1 |
| 2 | 3 | 0.8 | May,13 2015| 3 |
| 3 | 2 | 0.5 | May,12 2015| 2 |
You can sort on multiple columns like this:
select *
from QuizReport
where quiz_id = 1
order by points desc, time_spend asc;
select *
from (
select *
from QuizReport
where start_dt >= subdate(curdate(), 7)
order by points desc, time_spend asc) a
group by user_id;
group_by user_id preserves the first row for every user_id. since the inner query sorts rows by score, the outer query will display best row for every user.
I have a table like this:
name | day | score
------------------
John | 1 | 4
John | 2 | 5
John | 3 | 6
Marc | 1 | 7
Marc | 2 | 4
Marc | 3 | 5
Paul | 1 | 8
Paul | 2 | 2
Paul | 3 | 3
I want to get the sum of the score for each person, but only for certain days, sorted by this sum. let's say I want to get the score-sum of the 1. and 2. day, this is what I expect:
name | sum(score)
-----------------
Marc | 11
Paul | 10
John | 9
this is what failed:
SELECT name, sum(score) FROM mytable WHERE day<=2
I think I have to surround the sum(score)-part with some IF-statement, but I have no idea how.
Just add group by
SELECT name, sum(score) FROM mytable WHERE day<=2 group by name
Use sum function and group by clause for grouping the result.
query
select name,sum(score) as score
from myTable
where day in (1,2)
group by name
order by sum(score) desc;
fiddle demo
I'm trying to show in an index of videogame cheats and tips page where all the cheats available are listed, but i'm grouping the results by videogame and counting how many cheats the videogame has, this I can accomplish, but I'm trying to show the last added cheat to the game.
My query is:
SELECT a_games.game_id, COUNT(*) AS cheat_count, a_games.game_fname, a_games.game_logo, a_cheats.cheat_title FROM a_cheats
LEFT JOIN a_games ON a_games.game_id=a_cheats.game_id
GROUP BY a_cheats.game_id
this shows the first added cheat only.
I tried using max on cheat_id but the value cheat_title keeps showing the first added cheat.
Table a_cheats
cheat_id type_id member_id game_id cheat_title cheat_body cheat_date
1 | 1 | 1 | 22 | Truques V...| Introduz...| 2014-10-...|
2 | 1 | 1 | 25 | Invulnera...| Durante ...| 2014-10-...|
3 | 1 | 1 | 25 | Modo Debu...| Durante ...| 2014-10-...|
4 | 1 | 1 | 25 | Charme In...| Durante ...| 2014-10-...|
5 | 1 | 1 | 36 | Cabeças e...| Começa o...| 2014-10-...|
Table a_games
game_id genre_id member_id game_fname game_sname game_logo
22 | 15 | 1 | 4x4 Worl...| | 5259da0...
25 | 3 | 1 | Akuji th...| | 5287ae0...
36 | 25 | 1 | All Star...| | 5287daa...
So in the results Akuji the Heartless should show the cheat_title "Charme Infinito" which is the last added cheat for that game
query results
game_id game_count game_fname game_logo cheat_title
22 | 1 | 4x4 World Trophy | 5259da0527128_ava_4x4worldtrophy.jpg | Truques (Vários)
25 | 3 | Akuji The Heartless | 5287ae093e115_ava_akujiheartless.jpg | Invulnerabilidade
36 | 1 | All Star Tennis'99 | 5287daa2695ef_ava_allstartennis99.jpg| Cabeças e pés grandes
It seems once you call count(), you can't control which title to pick later on (it directly gets the title of the earliest entry).
Thus, we can do what you want by calling the count later.
note: you can change ORDER BY a_cheats.cheat_id DESC to ORDER BY a_cheats.cheat_date DESC if you want it to be more reliable.
SELECT gameID,gameName,cheatTitle, COUNT(gameID) AS cheat_count
FROM (
SELECT a_games.game_id as gameID, a_games.game_fname as gameName, a_cheats.cheat_title as cheatTitle
FROM a_cheats
JOIN a_games ON a_games.game_id=a_cheats.game_id
ORDER BY a_cheats.cheat_id DESC
) ungrouped
GROUP BY gameID
SQLFiddle: http://sqlfiddle.com/#!2/63f888/18
OR
SELECT gameID,gameName,cheatTitle, COUNT(cheatID) AS cheat_count
FROM (
SELECT a_games.game_id as gameID, a_games.game_fname as gameName, a_cheats.cheat_title as cheatTitle, a_cheats.cheat_id as cheatID
FROM a_cheats
RIGHT JOIN a_games ON a_games.game_id=a_cheats.game_id
ORDER BY a_cheats.cheat_id DESC
) ungrouped
GROUP BY gameID
SQLFiddle: http://sqlfiddle.com/#!2/63f888/19