我有一个带有大量测试/考试问题的SQLite数据库。每个问题属于一个问题类别。
我的表看起来像这样:
目标
我要做的是选择5个随机问题,但结果必须包含每个类别中的至少一个。目标是从每个类别中选择一组随机问题。
例如,输出可能是问题ID 1, 2, 5, 7, 8
,或2, 3, 6, 7, 8
或8, 6, 3, 1, 7
。
ORDER BY category_id,RANDOM()
我可以通过执行下面的SQL从SQLite中随机获得一系列问题,但是我如何确保结果中包含来自我的每个类别的问题?
基本上,我正在寻找像this这样的SQLite版本。
我想只获得5个结果,但每个类别中只有一个(或更多),结果集中包含所有类别。
恩惠
添加了赏金,因为我很好奇是否可以在SQLite中完成此操作。我可以在SQLite + Java中做到这一点,但有没有办法只在SQLite中执行此操作? :)
答案 0 :(得分:6)
答案的关键是结果中有两种问题:对于每个类别,一个必须约束来自该类别的问题;还有一些问题。
首先,受约束的问题:我们只选择每个类别中的一条记录:
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;
答案 1 :(得分:4)
基本上您要找的是选择前N个最大值。我早上花了3-4个小时来搜索它。 (我仍然没有成功,你可能需要再等几个小时)。
对于临时解决方案,您可以使用 group by 选项,如下所示,
String strQuery =“SELECT * FROM so_questions group by category_id;”;
输出如下,
将严格按照您的要求返回。
答案 2 :(得分:2)
因为它是sqlite(因此是本地的):在你有5个答案和4个不同的类别之前进行查询的速度有多慢,每次迭代都会删除重复的类别行。
我认为,如果每个类别都有相同的表示,那么你不太可能需要超过3次迭代,这仍然应该低于一秒。
这在算法上并不好,但对我来说,在SQL语句中使用random()无论如何都不算算。