views:

256

answers:

7
+1  Q: 

More elegant SQL?

Hi,

The query below is perfectly functional, and queries a single table to find the last 50 usernames added via a sequential userid number column.

Logic so far is to: find out the highest userid; subtract 50 from that; pull usernames back where greater.

However, it doesn't look elegant, and uses two subqueries to achieve it's goal:

SELECT username  
FROM table  
WHERE userid IN  
  (SELECT userid  
   FROM table  
   WHERE userid >  
    (SELECT MAX(userid) -50  
     FROM table))

Is there a way to make this less nested? More efficient? More elegant? Any help would be much appreciated, as this can't be the best way!

Cheers & many thanks
Ali

A: 

Depends on the database you use, but try something like this:

oracle: select username from table where rownum < 50 order by userid;

postgresql: select username from table order by userid limit 10;

Marcin Cylke
rownum index starts @ 1 and not 0 so you'll need a less-than-equals to get 50 rows. that only returns 49.
Eoin Campbell
Your Oracle solution doesn't work because Oracle executes first the where rownum < 50, only after that it will execute the order by. See also Eoin Campbell.
tuinstoel
A: 

Purely for aesthetic I use SQLinForm which is a Java applet that formats your SQL very nicely. It's flexible with a lot of options too.

joshcomley
To whoever voted this down, he asked about elegance and I did point out this was purely for aesthetic; elegant code should be readable in both it's format and it's code...
joshcomley
A: 

how about:

SELECT username FROM table ORDER BY userid DESC LIMIT 50
Adrian Mester
There's going to be a reason for the subqueries.
Henrik P. Hessel
That's MySql .
Eoin Campbell
The reason for the subquery is so it can pick up the last 50 users, rather than any users with a userid > 50. i.e. userid > max(userid)-50
Ali J
Ali J, I'm pretty sure that's what it does (although in MySQL). It retrieves the greatest 50 userid's. The difference from the original post is that in the original, if you delete some users, you would get less results
Adrian Mester
A: 

If you would have a DateCreated field in the user table, you could make the query like this:

SELECT TOP 50 username
FROM table 
ORDER BY DateCreated DESC
fretje
That's SQL Server syntax
Eoin Campbell
I'm sorry, didn't see the oracle tag... isn't there an oracle equivalent for the "TOP x" clause?
fretje
Oracle uses "WHERE RowNum <= X"; RowNum being a special Oracle column
Andomar
+2  A: 
SELECT * FROM (SELECT UserName FROM Table ORDER BY UserID DESC) 
WHERE RowNum <= 50

... I think... been a while since I fiddled with Oracle.

This is roughly the same as

SELECT Top 50 in SQLServer

and

SELECT ... LIMIT 50 in MySql

Eoin Campbell
@HankGay nice spot. cheers
Eoin Campbell
+6  A: 

The answers provided are along the right lines. You can use ROWNUM to select TOP-N style results.

Please be careful though and note that the rownum is assigned to the query results after predication but before the ORDER BY. Try something like the following:

SELECT username  
FROM 
  (SELECT username  
   FROM table  
   ORDER BY userid DESC)
WHERE rownum <= 50
ChrisCM
Following on from my answer, you should find this very useful: http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
ChrisCM
Many thanks for a good answer and the link, ChrisCM. This works nicely.
Ali J
+2  A: 

You can use ROW_NUMBER() to assign a number to each row, based on its position in an ordered list. For example, to number rows starting with 1 for the highest userid:

SELECT username
FROM (
    SELECT 
         ROW_NUMBER() OVER (ORDER BY user_id DESC) AS RowNr,
         *
    FROM users
) sub
WHERE RowNr < 50

Unlike the query in the question, this will work if userid is not consecutive.

Andomar