Matt O'Connell
Matt O'Connell

Reputation: 287

How can I select a random row from a SQL query selection?

How can I select a row at random from a SQL database query? By this I mean:

Select all things with Category 'green' from table1:

$stmt = $db->query('SELECT * from table1 WHERE Category LIKE "%green%"');

Then randomly display a row from this selection (as opposed to displaying every row from this selection as I've done below)

while($rows = $stmt->fetch()){
     echo "<tr><td>". $rows['Number'] . "</td><td>" . $rows['Content'] . "</td></tr>";
};

Upvotes: 1

Views: 2028

Answers (4)

George Cummins
George Cummins

Reputation: 28906

In a reasonably-sized data set, order your rows randomly and select the first one:

...ORDER BY RAND() LIMIT 1;

Your statement will become:

$stmt = $db->query(
    'SELECT * from table1
     WHERE Category LIKE "%green%"
     ORDER BY RAND() LIMIT 1;'
);

If you narrow your selection in your query, you will not need to use a messy process to extract a single row from the result set in your PHP code.

If your data set is very large, consider executing multiple queries as recommended by Tobias Hagenbeek:

  1. COUNT() the matching rows.
  2. In PHP, select a random number between 1 and the result of COUNT().
  3. Perform new query to select the specified row:

    ...LIMIT <random number>, 1;

Finally, if you need only a single, arbitrary row and randomness/uniqueness is not an issue, consider selecting the first row from the table every time as suggested by Gordon Linoff:

...LIMIT 1;

Upvotes: 5

Gordon Linoff
Gordon Linoff

Reputation: 1269503

If you want only one row from the set of all rows, then the fastest method is simply:

 SELECT *
 from table1
 WHERE Category LIKE "%green%"
 LIMIT 1;

This will give you the first row encountered in the data. To a close approximation, this is the first row inserted into the table that matches your criteria. (This is not a guarantee. For instance, deletes could definitely change this.)

This has the advantage of being fast'ish, which is useful because an index will not benefit you on the where clause. In this case, the query does a full table scan but stops at the first match.

The alternative for a truly random row is to use rand():

SELECT *
from table1
WHERE Category LIKE "%green%"
order by rand()
limit 1;

This requires a full table scan that doesn't stop because all matches are needed for the sort. You then have the additional overhead of sorting the subset by rand(). There are some alternatives, if performance really is an issue.

Upvotes: 0

Tobias Hagenbeek
Tobias Hagenbeek

Reputation: 1213

You could use ORDER BY RAND(), but you should be weary to do so. Especially if you are talking large systems, and more then 10k rows.

Here's why...

What happens when you run such a query? Let’s say you run this query on a table with 10000 rows, than the SQL server generates 10000 random numbers, scans this numbers for the smallest one and gives you this row. Generating random numbers is relatively expensive operation, scaning them for the lowest one (if you have LIMIT 10, it will need to find 10 smallest numbers) is also not so fast (if quote is text it’s slower, if it’s something with fixed size it is faster, maybe because of need to create temporary table).

So what you should do is a count on your rows, take a random number between 0 and your count-1, then do SELECT column FROM table LIMIT $generated_number, 1

Upvotes: 0

Tasos Bitsios
Tasos Bitsios

Reputation: 2789

The easy way is this:

$stmt = $db->query('SELECT * from table1 WHERE Category LIKE "%green%" ORDER BY RAND()');

ORDER BY RAND() will order the results randomly, but it is a bit expensive as an operation (link).

If you care about that sort of thing, you can alternatively query for the number of rows in the table, then do $r = rand(0, $count-1), then LIMIT 1 OFFSET $r at the end of your query.

Upvotes: 0

Related Questions