Retain ordering from IN subquery
this should be an easy one, but I can't seem to get mysql to play ball.
I'm trying to build a list of projects that a user most recently voted for, to be used on that users profile page.
I have table of votes, containing uid(INT), project(INT), timestamp(INT)
And a table of projects whose id field matches the project field in the votes table.
My initial query was
SELECT * FROM projects WHERE id IN(SELECT project FROM votes WHERE uid=x ORDER BY timestamp DESC);
This gives a correct list, but the ordering is messed up. I also realised that I had forgotten to add DISTINCT project to the subquery, but for some reason it was giving distinct projects anyway.
SELECT project FROM votes WHERE uid=x ORDER BY timestamp DESC;
On its own gives the correct ordering as expected, but as soon as I query from that, the ordering is discarded.
I must not understand how nested statements work, could someone help, and also explain why the DISTINCT keyword is not necessary to get distinct project ids from the votes table!?
An example as requested;
The votes table contains individual votes, so if a user votes for a project three times, it might look like this;
uid project timestamp
34 9 10984
34 9 11093
34 9 11309
If that user (34 in the example) then voted for a different project, the votes table would now look like;
uid project timestamp
34 9 10984
34 9 11093
34 9 11309
34 21 12612
The indicies 9 and 21 are then used to query the projects table. So for example the projects table might contain;
id name description
9 Proj开发者_Go百科ect A This is project A.
21 Project B This is project B.
What I want is the list of projects that the user most recently voted for. So in this case I want to grab projects 21 and 9 from the projects table in that order, 21 then 9 and on into projects that the user voted for further into the past.
I would use a join here instead of a subquery.
SELECT p.*
FROM projects p
INNER JOIN votes v
ON p.id = v.project
WHERE v.uid = x
ORDER BY v.timestamp DESC;
try with ORDER BY FIELD
- something like:
SELECT * FROM projects WHERE id IN(SELECT project FROM votes WHERE uid=x ORDER BY timestamp DESC) ORDER BY FIELD(id, (SELECT project FROM votes WHERE uid=x ORDER BY timestamp DESC) );
DISTINCT
is not necessary because even though the IN()
subquery may return duplicates, the outer query is merely looking for matching values among those, not 1:1 relationships. This is different than JOIN
behavior, where you would likely end up with duplicate rows.
It's similar to saying you have an array [1,2,2,4,5,5]
and asking which of the values from a different array [1,2,5,6]
occur anywhere in the first array. The answer is always [1,2,5]
. Hopefully this illustration isn't more confusing. I'll edit it as I think of ways to improve it.
Previous answers supply the correct ORDER BY
.
You can rewrite this as a join:
SELECT DISTINCT projects.* FROM projects
JOIN votes ON projects.id = votes.project
ORDER BY timestamp DESC
精彩评论