views:

282

answers:

5

I would like to take a database of say, 1000 users and select 20 random ones (ORDER BY rand(),LIMIT 20) then order the resulting set by the names. I came up with the following query which is not working like I hoped.

SELECT * FROM users WHERE 1 ORDER BY rand(), name ASC LIMIT 20

+4  A: 

Use a subquery:

SELECT * FROM 
(
    SELECT * FROM users ORDER BY rand() LIMIT 20
) T1
ORDER BY name 

The inner query selects 20 users at random and the outer query orders the selected users by name.

Mark Byers
Awesome, two things. Why the `T1` after the query, what's it's purpose? Second: Do you know if it's possible to use a subquery in datamapper?
Josh K
Ah, so you're casting that inner select as a new temporary table. Got it.
Josh K
@Josh K: Regarding your first question, it's called an alias. If you omit it you get this error: `Every derived table must have its own alias`.
Mark Byers
@Mark: Yep, I just tried that and realized what it was doing.
Josh K
+1  A: 
SELECT  *
FROM    (
        SELECT  *
        FROM    users
        WHERE   1
        ORDER BY
                rand()
        LIMIT 20
        ) q
ORDER BY
        name
Quassnoi
+1  A: 

Use a subquery:

SELECT * FROM (
    SELECT * FROM users ORDER BY RAND() LIMIT 20
) u
ORDER BY name

or a join to itself:

SELECT * FROM users u1
INNER JOIN (
    SELECT id FROM users ORDER BY RAND() LIMIT 20
) u2 USING(id)
ORDER BY u1.name
Alexander Konstantinov
+2  A: 

Beware of ORDER BY RAND() because of performance and results. Check this article out: http://jan.kneschke.de/projects/mysql/order-by-rand/

ircmaxell
Agree, its possibly the worst performing query.
mhughes
Additional WHERE constraints put the RAND load on about at most 500 rows. This is not a huge table, performance is not an issue.
Josh K
A: 

Instead of using a subquery, you could use two separate queries, one to get the number of rows and the other to select the random rows.

SELECT COUNT(id) FROM users; #id is the primary key

Then, get a random twenty rows.

$start_row = mt_rand(0, $total_rows - 20);

The final query:

SELECT * FROM users ORDER BY name ASC LIMIT $start_row, 20;
Exception