答案的关键在于结果中有两种问题:对于每个类别,必须限制一个问题来自该类别;和一些剩余的问题。
首先,受限问题:我们只从每个类别中选择一条记录:
SELECT id, category_id, question_text, 1 AS constrained, max(random()) AS r
FROM so_questions
GROUP BY category_id
(此查询依赖于 SQLite 3.7.11(在 Jelly Bean 或更高版本中)中引入的功能:在查询SELECT a, max(b)
中,保证的值a
来自具有最大值的记录b
。)
我们还必须得到非约束问题(过滤掉已经在约束集中的重复项将在下一步发生):
SELECT id, category_id, question_text, 0 AS constrained, random() AS r
FROM so_questions
当我们将这两个查询与 组合UNION
然后按 分组时id
,我们将所有重复项放在一起。然后选择max(constrained)
确保对于具有重复项的组,仅保留受约束的问题(而所有其他问题无论如何每组只有一条记录)。
最后,该ORDER BY
子句确保首先出现受限问题,然后是一些随机的其他问题:
SELECT *, max(constrained)
FROM (SELECT id, category_id, question_text, 1 AS constrained, max(random()) AS r
FROM so_questions
GROUP BY category_id
UNION ALL
SELECT id, category_id, question_text, 0 AS constrained, random() AS r
FROM so_questions)
GROUP BY id
ORDER BY constrained DESC, r
LIMIT 5
对于较早的 SQLite/Android 版本,我还没有找到不使用临时表的解决方案(因为受约束问题的子查询必须多次使用,但不会保持不变,因为random()
):
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE constrained AS
SELECT (SELECT id
FROM so_questions
WHERE category_id = cats.category_id
ORDER BY random()
LIMIT 1) AS id
FROM (SELECT DISTINCT category_id
FROM so_questions) AS cats;
SELECT ids.id, category_id, question_text
FROM (SELECT id
FROM (SELECT id, 1 AS c
FROM constrained
UNION ALL
SELECT id, 0 AS c
FROM so_questions
WHERE id NOT IN (SELECT id FROM constrained))
ORDER BY c DESC, random()
LIMIT 5) AS ids
JOIN so_questions ON ids.id = so_questions.id;
DROP TABLE constrained;
COMMIT TRANSACTION;