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
Related
i have 2 tables (Titles and Episodes).
Table Titles
id | title | type | views
------------------------------
1 | Lucy | movie | 300
2 | Narcos | series | 2600
3 | Ip Man | movie | 120
4 | Creed | movie | 460
Table Episodes
id | title_id | title | episode | views
----------------------------------------------
1 | 2 | episode1 | 1 | 100
2 | 2 | episode2 | 2 | 260
3 | 2 | episode3 | 3 | 96
4 | 2 | episode4 | 4 | 210
Now i use this query to get most viewed episodes.
SELECT titles.id, titles.title, episodes.title_id, episodes.episode, episodes.views FROM titles, episodes WHERE titles.id = episodes.title_id ORDER BY episodes.views DESC LIMIT 0, 16
And i use this query for movies.
SELECT titles.id, titles.title, titles.views WHERE type = 'movie' ORDER BY titles.views DESC LIMIT 0, 16
I want to combine this two last queries into 1 temporary table to show most viewed movies and episodes.
Temporary Table
id | title_id | title | views
----------------------------------------------
1 | 4 | Creed | 460
2 | 1 | Lucy | 300
3 | 2 | Narcos Episode 2 | 260
4 | 2 | Narcos Episode 4 | 210
How can i do that ?
Thank you.
you can use view
see this page to more information
http://dev.mysql.com/doc/refman/5.7/en/create-view.html
I got it, thank you #sagi
(SELECT titles.id as title_id, concat(titles.title,' ',episodes.title) as
title,episodes.views as views
FROM titles, episodes
WHERE titles.id = episodes.title_id and type = 'series'
ORDER BY episodes.views DESC LIMIT 0, 16)
UNION ALL
(SELECT titles.id, titles.title, titles.views as views
FROM titles
WHERE type = 'movie'
ORDER BY titles.views DESC LIMIT 0, 16) ORDER BY views DESC
I have SQL (MySQL) that I've can't figure out. The application is using uploaded photos where there are many tagged participants in a photo and there is the possibility to give photos a vote between 1 to 5.
The original query gets all the votes for a photo and orders them by amount of votes and the average of those votes.
Now I need to limit the returned photos by the ones with more than 1 participant. So photos with only 1 participant should not be accounted for.
Simplified schema looks like this.
PHOTOS
----------------------
| id | title |
----------------------
| 1 | Fun stuff |
| 2 | Crazy girls |
| 3 | Single boy |
PHOTO_VOTES
-------------------------------------------
| photo_id | grade | date | user_id |
-------------------------------------------
| 1 | 3 | … | 12 |
| 1 | 3 | … | 12 |
| 2 | 5 | … | 14 |
| 2 | 4 | … | 14 |
| 3 | 4 | … | 15 |
| 3 | 4 | … | 18 |
PHOTO_PARTICIPANTS
-------------------------
| photo_id | user_id |
-------------------------
| 1 | 12 |
| 1 | 21 |
| 1 | 33 |
| 2 | 14 |
| 2 | 33 |
| 3 | 12 |
This is how far I got:
SELECT vote.photo_id,
COUNT(vote.photo_id) AS vote_count,
AVG(vote.grade) AS vote_average,
COUNT(pp.photo_id) AS participant_count
FROM photo_votes vote
LEFT JOIN photos p ON (vote.photo_id = p.id)
LEFT JOIN photo_participants pp ON (pp.photo_id = p.id)
GROUP BY vote.post_id,
HAVING vote_count >= 2
AND vote_average >= 3
AND participant_count > 1
ORDER BY count DESC, average DESC;
Basically what I'm looking for to end up with, excluding the photo with only one participant:
VOTES
-----------------------------------------------------------
| photo_id | vote_count | average | participant_count
-----------------------------------------------------------
| 1 | 2 | 3 | 3
| 2 | 2 | 4.5 | 2
Update
It turned out this is a very inefficient way of trying to do what I want. Gordons answer below did solve the problem, but as soon as I wanted to join fields from the photos table as well, the "cartesian product"-issue became a real problem - it became a very heavy and slow query.
The solution I finally ended up with is adding a cache-field into the photos table keeping track of how many participants are in the photo. In other words I added a 'participant_count' field to 'photos' that is being updated every time a change is made to the participants table. I also run a cron-job regularly to make sure all photos 'participant_count' are properly up-to-date.
First, you don't need left joins for this. But that shouldn't affect the results. The problem is that you have a cartesian product, because you have two 1-n relationships to photos: votes and participants.
The proper way to fix this is by using subqueries:
SELECT pv.photo_id, pv.vote_count, pv.vote_average, pp.participant_count
FROM (SELECT pv.photo_id, count(*) AS vote_count, avg(grade) AS vote_average
FROM photo_votes pv
GROUP BY pv.photo_id
) pv
JOIN
(SELECT pp.photo_id, count(*) AS participant_count
FROM photo_participants p;
GROUP bY pv.photo_id
) pp
ON pv.photo_id = pp.photo_id
WHERE pv.vote_count >= 2 AND
pv.vote_average >= 3 AND
pp.participant_count > 1
ORDER BY pv.vote_count DESC, pv.vote_average DESC;
Note that you don't even need the photos table, because you are not using any fields in it.
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.
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.
I'm having trouble coming up with a query that returns the player's id, name along with the player's first match date, matchid and opponent.
I want the same information for player's last match as well.
`players`
id | name
1 | playername10
2 | playername22
3 | playername33
4 | playername45
5 | playername55
`matches`
id | gamedate | opponent
1 | 2011-01-01 | opponent1
2 | 2011-01-02 | opponent2
3 | 2011-01-03 | opponent3
4 | 2011-01-04 | opponent4
5 | 2011-01-05 | opponent5
`playermatchscores`
id | matchid | player | goals
1 | 1 | playername10 | 1
2 | 1 | playername22 | 2
3 | 2 | playername10 | 1
4 | 1 | playername33 | 1
5 | 3 | playername45 | 2
6 | 4 | playername55 | 1
7 | 2 | playername55 | 1
8 | 3 | playername22 | 2
9 | 5 | playername55 | 1
Where matchid is a foreign key to the id in table matches.
I tried several queries but I may be approaching it the the wrong way. How can I write a way to get the information I want?
Information about LEFT JOIN: http://www.w3schools.com/sql/sql_join_left.asp
SELECT players.id, MAX(matches.gamedate) AS first_match, MIN(matches.gamedate) AS last_match
FROM playermatchscores
LEFT JOIN players ON players.player = playermatchscores.player
LEFT JOIN matches ON matches.id = playermatchscores.matchid
GROUP BY players.player
I haven't tested this select.
P.S. You should use foreign key for players table too with player_id in playermatchscores.
After the changes in question:
SELECT players.*, matches.*,
FROM playermatchscores
LEFT JOIN players ON players.name = playermatchscores.player
LEFT JOIN matches ON matches.id = playermatchscores.matchid
ORDER BY matches.gamedate ASC
WHERE players.id = 3
LIMIT 1
For the last match replace ASC with DESC.
P.S. This is not the best way to do it but it should work.