从每个类别中选择至少一个?

Ter*_*ler 7 database sqlite random android

SQLFiddle链接

我有一个带有一堆测试/考试问题的SQLite数据库.每个问题属于一个问题类别.

我的表看起来像这样:
so_questions表

目标
我要做的是选择5个随机问题,但结果必须至少包含每个类别中的一个.目标是从每个类别中选择一组随机问题.

例如,输出可以是问题ID 1, 2, 5, 7, 8,2, 3, 6, 7, 8或者8, 6, 3, 1, 7.

ORDER BY category_id,RANDOM()
我可以通过执行下面的SQL从SQLite中获取一个随机的问题列表,但是我如何确保结果包含来自我的每个类别的问题?

SELECT ORDER BY category_id,随机

基本上,我正在寻找像这样的SQLite版本.

我想只获得5个结果,但每个类别中只有一个(或更多)结果,结果集中包含所有类别.

赏金
添加了赏金,因为我很好奇是否可以在SQLite中完成此任务.我可以在SQLite + Java中做到这一点,但有没有办法在SQLite中做到这一点?:)

SQLFiddle链接

CL.*_*CL. 6

答案的关键是结果中有两种问题:对于每个类别,一个必须限制来自该类别的问题; 还有一些问题.

首先,受约束的问题:我们只从每个类别中选择一条记录:

SELECT id, category_id, question_text, 1 AS constrained, max(random()) AS r
FROM so_questions
GROUP BY category_id
Run Code Online (Sandbox Code Playgroud)

(此查询依赖于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
Run Code Online (Sandbox Code Playgroud)

当我们将这两个查询组合起来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
Run Code Online (Sandbox Code Playgroud)

对于早期的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;
Run Code Online (Sandbox Code Playgroud)