在SQLite中选择随机行

时间:2010-11-06 20:07:23

标签: sql sqlite

在MySQL中,您可以使用以下语句选择X随机行:

SELECT * FROM table ORDER BY RAND() LIMIT X

然而,这不适用于SQLite。有没有等价的?

6 个答案:

答案 0 :(得分:65)

对于更好的性能使用:

SELECT * FROM table WHERE id IN (SELECT id FROM table ORDER BY RANDOM() LIMIT x)

SQL引擎首先将行的预计字段加载到内存然后对它们进行排序,这里我们只是对内存中每行的id字段进行随机排序,因为它已编入索引,然后将它们分开,并使用这些X ID找到整行。

因此,随着表的增长,这会占用更少的RAM和CPU!

答案 1 :(得分:58)

SELECT * FROM table ORDER BY RANDOM() LIMIT X

答案 2 :(得分:8)

SELECT * FROM table ORDER BY RANDOM() LIMIT 1

答案 3 :(得分:2)

此处的所有答案均基于ORDER BY。对于大型集合,非常效率低(即无法使用),因为您将为每条记录评估RANDOM(),然后ORDER BY这是一项资源昂贵的操作。

另一种方法是将abs(CAST(random() AS REAL))/9223372036854775808 < 0.5放在WHERE子句中,以获得0.5例命中率。

SELECT *
FROM table
WHERE abs(CAST(random() AS REAL))/9223372036854775808 < 0.5

大数是random()可以产生的最大绝对数。 abs()是因为它已签名。结果是0到1之间的均匀分布随机变量。

这有其缺点。您无法保证结果,如果阈值与表相比较大,则所选数据将偏向表的开头。但在一些精心设计的情况下,它可能是一个可行的选择。

答案 4 :(得分:2)

接受的答案有效,但需要对每个查询进行全表扫描。随着您的表变大,这将变得越来越慢,从而使最终用户触发的查询存在风险。

以下解决方案利用索引在 O(log(N)) 时间内运行。

SELECT * FROM table
WHERE rowid > (
  ABS(RANDOM()) % (SELECT max(rowid) FROM table)
)
LIMIT 1;

分解

  • SELECT max(rowid) FROM table - 返回表的最大有效 rowid。 SQLite is able to use the index on rowid 以高效运行。
  • ABS(RANDOM()) % ... - 返回一个介于 0 和 max(rowid) - 1) 之间的随机数。 SQLite's random function 生成一个介于 -9223372036854775808 和 +9223372036854775807 之间的数字。 ABS 确保其为正数,模运算符将其在 max(rowid) - 1 之间进行门控。
  • rowid > ... - 如果生成的随机数对应于已删除的行,请使用 = 而不是使用 >。使用严格大于可确保我们返回行 ID 介于 1(大于 0)和 max(rowid)(大于 max(rowid) - 1)之间的行。 SQLite 也使用主键索引来有效地返回此结果。

这也适用于带有 WHERE 子句的查询。将 WHERE 子句应用于输出和 SELECT max(rowid) 子查询。但是,我不确定这将在哪些条件下有效运行。

注意:这是从 an answer in a similar question 派生的。

答案 5 :(得分:0)

这解决了负RANDOM整数,并在大型数据集上保持了良好的性能:

SELECT * FROM table LIMIT 1 OFFSET abs(random() % (select count(*) from table));

其中:
abs(random() % n )range(0,n)中给您一个正整数