I have this table for documents (simplified version here):
+------+-------+--------------------------------------+
| id | rev | content |
+------+-------+--------------------------------------+
| 1 | 1 | ... |
| 2 | 1 | ... |
| 1 | 2 | ... |
| 1 | 3 | ... |
+------+-------+--------------------------------------+
How do I select one row per id and only the greatest rev?
With the above data, the result should contain two rows: [1, 3, ...]
and [2, 1, ..]
. I'm using MySQL.
Currently I use checks in the while
loop to detect and over-write old revs from the resultset. But is this the only method to achieve the result? Isn't there a SQL solution?
Update
As the answers suggest, there is a SQL solution, and here a sqlfiddle demo.
Update 2
I noticed after adding the above sqlfiddle, the rate at which the question is upvoted has surpassed the upvote rate of the answers. That has not been the intention! The fiddle is based on the answers, especially the accepted answer.
My preference is to use as little code as possible...
You can do it using
IN
try this:to my mind it is less complicated... easier to read and maintain.
This solution makes only one selection from YourTable, therefore it's faster. It works only for MySQL and SQLite(for SQLite remove DESC) according to test on sqlfiddle.com. Maybe it can be tweaked to work on other languages which I am not familiar with.
None of these answers have worked for me.
This is what worked for me.
I am flabbergasted that no answer offered SQL window function solution:
Added in SQL standard ANSI/ISO Standard SQL:2003 and later extended with ANSI/ISO Standard SQL:2008, window (or windowing) functions are available with all major vendors now. There are more types of rank functions available to deal with a tie issue:
RANK, DENSE_RANK, PERSENT_RANK
.here is another solution hope it will help someone
You can make the select without a join when you combine the
rev
andid
into onemaxRevId
value forMAX()
and then split it back to original values:This is especially fast when there is a complex join instead of a single table. With the traditional approaches the complex join would be done twice.
The above combination is simple with bit functions when
rev
andid
areINT UNSIGNED
(32 bit) and combined value fits toBIGINT UNSIGNED
(64 bit). When theid
&rev
are larger than 32-bit values or made of multiple columns, you need combine the value into e.g. a binary value with suitable padding forMAX()
.