简体   繁体   中英

Random row from random derived table

I've a set of tables and I want to select a random row from within a random one of the tables.

If there's 5 tables

Table1
Table2
Table3
Table4
Table5

Each has the same data format.

I've tried the below, the first part in selecting a random table works but grabbing the info from the table is returning 0 rows.

 SELECT * FROM (SELECT `cat_table_name` from `category-defines` GROUP BY `cat_table_name` LIMIT 1) AS x ORDER BY RAND() LIMIT 3

Not every task can be done in a single SQL query.

In SQL, all table names (really, all identifiers) must be fixed at the time the query is parsed. You can't write an SQL query that makes choices of tables (or columns, etc.) based on expressions evaluated during the query.

By analogy: it would be like in any other code, trying to call a function whose name is based on the return value of the function you want to call.

So you can't do what you want in one query.

You could pick the random table name in one query, then use that result as you form the next query.

SELECT `cat_table_name` from `category-defines` GROUP BY `cat_table_name` LIMIT 1

SELECT * FROM `$result_from_previous_query` ORDER BY RAND() LIMIT 3

That's the simplest solution.

Be sure to delimit your table name in back-ticks, just in case one of the table names is FROM or some other reserved keyword .

(Note: the first query above doesn't pick a random table name, it always picks the first table).

A comment above suggests a UNION of all the tables. This is what that would look like:

SELECT *
FROM 
(SELECT FLOOR(RAND()*5)+1 AS table_num) AS r
JOIN (
    (SELECT 1 AS table_num, * FROM my_table1 ORDER BY RAND() LIMIT 3)
    UNION
    (SELECT 2 AS table_num, * FROM my_table2 ORDER BY RAND() LIMIT 3)
    UNION
    (SELECT 3 AS table_num, * FROM my_table3 ORDER BY RAND() LIMIT 3)
    UNION
    (SELECT 4 AS table_num, * FROM my_table4 ORDER BY RAND() LIMIT 3)
    UNION
    (SELECT 5 AS table_num, * FROM my_table5 ORDER BY RAND() LIMIT 3)
) AS x USING (table_num) 

But this has at least two problems:

  • It bears the performance cost of picking random rows from every table, just to throw away most of them. Wasteful.
  • You still have to know the table names in advance, so if they aren't fixed, you end up running another query before this one to get the list of table names.

That is because the main query will be executed on the result of the derived table (in this case the table name), not the actual table name.

As far as my MySQL knowledge stretches you have to split this into two queries, where the first query retrieves the table name and the second query uses the result from the first query. In PHP it would look something like this

//get a random table name
$stmt = $this->pdo->prepare('SELECT `cat_table_name` as table from `category-defines` GROUP BY `cat_table_name` LIMIT 1');
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);

//select 3 random rows with the table name
$stmt = $this->pdo->prepare('SELECT * FROM '.$row['table'].' ORDER BY RAND() LIMIT 3');

$stmt->execute();
$randomRows = $stmt->fetchAll(PDO::FETCH_ASSOC); //the three random rows

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM