MySQL限制到一定数量 - 取决于先前的子查询

时间:2016-11-20 18:42:29

标签: mysql sql subquery limit

我正在尝试构建一个SQL查询,该查询随机选择不同表中的条目,最多可达一定数量。

假设我有3个表A,B和C.我想从A,B和C中选择总共10行。

现在我想从A中随机选择2个条目,最多从B中选择6个条目(取决于从A中检索到的数量。如果A没有任何行,我想从B中获取6行。如果A返回1行,我想从B获得5行,依此类推..)。然后我想用C中随机选择的行填充剩余的条目(0到10之间,具体取决于之前的子查询)。 到目前为止,我已经尝试过:

select * from (
(SELECT * FROM A  ORDER BY RAND() LIMIT 2)
UNION
(SELECT * FROM B ORDER BY RAND())
limit 4) a

不幸的是,只要我将两个子查询联合起来,第二个查询的随机排序就会丢失,而且我总是从B中检索相同的前4行。 这可能只使用SQL,还是我必须进行多个查询并以编程方式将它们联合起来?

祝你好运

2 个答案:

答案 0 :(得分:0)

使用CTE,以便您可以获取从表A和B中选择的行的计数。像这样:

with a_rows as (
    select * from table_a order by random() limit 2
    ),
b_rows as (
    select * from table_b order by random() limit 6 - (select count(*) from a_rows)
    ),
c_rows as (
    select * from table_c order by random() limit 10 - (select count(*) from b_rows)

select * from a_rows
union
select * from b_rows
union
select * from c_rows;

请注意,CTE是MySQL功能集的最新成员。

或者,您可以使用单独的查询而不是CTE。

答案 1 :(得分:0)

您可以使用以下查询执行此操作:

SELECT * FROM (
    SELECT * FROM (
        SELECT ab.* FROM (
            SELECT * FROM ( SELECT 1 as level,a.* FROM table_a AS a ORDER BY RAND() LIMIT 2) atmp
            UNION
            SELECT * FROM ( SELECT 2 as level ,b.* FROM table_b AS b ORDER BY RAND() LIMIT 6 ) btmp
        ) AS ab ORDER BY ab.level LIMIT 6
    ) AS totab
UNION ALL
    SELECT * FROM ( SELECT 3 as level,c.* FROM table_c AS c ORDER BY RAND() LIMIT 10) ctmp
) AS totabc ORDER BY totabc.level LIMIT 10;

样本表

mysql> select * from table_a;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+
4 rows in set (0,00 sec)

mysql> select * from table_b;
+----+
| id |
+----+
| 11 |
| 22 |
| 33 |
| 44 |
| 55 |
| 66 |
| 77 |
+----+
7 rows in set (0,00 sec)

mysql> select * from table_c;
+--------+
| id     |
+--------+
|    111 |
|    222 |
|    333 |
|    444 |
|    555 |
|    666 |
|    777 |
|    888 |
|    999 |
| 101010 |
| 111111 |
+--------+
11 rows in set (0,00 sec)

示例查询

mysql> SELECT * FROM (
    ->     SELECT * FROM (
    ->         SELECT ab.* FROM (
    ->             SELECT * FROM ( SELECT 1 as level,a.* FROM table_a AS a ORDER BY RAND() LIMIT 2) atmp
    ->             UNION
    ->             SELECT * FROM ( SELECT 2 as level ,b.* FROM table_b AS b ORDER BY RAND() LIMIT 6 ) btmp
    ->         ) AS ab ORDER BY ab.level LIMIT 6
    ->     ) AS totab
    -> UNION ALL
    ->     SELECT * FROM ( SELECT 3 as level,c.* FROM table_c AS c ORDER BY RAND() LIMIT 10) ctmp
    -> ) AS totabc ORDER BY totabc.level LIMIT 10;
+-------+--------+
| level | id     |
+-------+--------+
|     1 |      1 |
|     1 |      4 |
|     2 |     11 |
|     2 |     33 |
|     2 |     66 |
|     2 |     55 |
|     3 |    333 |
|     3 | 111111 |
|     3 |    777 |
|     3 |    888 |
+-------+--------+
10 rows in set (0,00 sec)

mysql>