Ale*_*der 110 sqlite random row
我有一个sqlite
包含以下架构的表:
CREATE TABLE foo (bar VARCHAR)
Run Code Online (Sandbox Code Playgroud)
我正在使用此表作为字符串列表的存储.
如何从此表中选择随机行?
Adr*_*der 195
SELECT * FROM table ORDER BY RANDOM() LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
Suz*_*ron 29
以下解决方案比anktastic快得多(计数(*)成本很高,但如果你可以缓存它,那么差异不应该那么大),它本身比"random by random()"要快得多.当你有大量的行时,虽然它们有一些不便之处.
如果您的rowid相当紧凑(即少数删除),那么您可以执行以下操作(使用(select max(rowid) from foo)+1
而不是max(rowid)+1
提供更好的性能,如注释中所述):
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
Run Code Online (Sandbox Code Playgroud)
如果你有洞,你有时会尝试选择一个不存在的rowid,而select将返回一个空的结果集.如果这是不可接受的,您可以提供如下默认值:
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1)) or rowid = (select max(rowid) from node) order by rowid limit 1;
Run Code Online (Sandbox Code Playgroud)
第二种解决方案并不完美:最后一行(具有最高rowid的那一行)的概率分布较高,但如果你经常向表中添加东西,它将成为一个移动目标,概率的分布应该是好多了.
还有另一种解决方案,如果您经常从具有大量空洞的表中选择随机内容,那么您可能希望创建一个包含按随机顺序排序的原始表行的表:
create table random_foo(foo_id);
Run Code Online (Sandbox Code Playgroud)
然后,在periodicalliy中,重新填充表random_foo
delete from random_foo;
insert into random_foo select id from foo;
Run Code Online (Sandbox Code Playgroud)
要选择一个随机行,您可以使用我的第一个方法(这里没有漏洞).当然,最后一种方法存在一些并发性问题,但是重新构建random_foo是一种不太经常发生的维护操作.
然而,我最近在邮件列表中找到的另一种方法是在删除时设置触发器,将具有最大rowid的行移动到当前删除的行中,这样就不会留下任何漏洞.
最后,请注意rowid和整数主键自动增量的行为不相同(使用rowid,当插入新行时,选择max(rowid)+1,其中它是高亮值,有史以来+ 1为一个主键),所以最后的解决方案不适用于random_foo中的自动增量,但其他方法将.
And*_*sky 16
关于什么:
SELECT COUNT(*) AS n FROM foo;
Run Code Online (Sandbox Code Playgroud)
然后在[0,n)中选择一个随机数m
SELECT * FROM foo LIMIT 1 OFFSET m;
Run Code Online (Sandbox Code Playgroud)
您甚至可以在某处保存第一个数字(n),并仅在数据库计数更改时更新它.这样你就不必每次都做SELECT COUNT.
Rob*_*óes 15
您需要在查询中输入"按RANDOM()排序".
例:
select * from quest order by RANDOM();
Run Code Online (Sandbox Code Playgroud)
让我们看一个完整的例子
CREATE TABLE quest (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quest TEXT NOT NULL,
resp_id INTEGER NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
插入一些值:
insert into quest(quest, resp_id) values ('1024/4',6), ('256/2',12), ('128/1',24);
Run Code Online (Sandbox Code Playgroud)
默认选择:
select * from quest;
| id | quest | resp_id |
1 1024/4 6
2 256/2 12
3 128/1 24
--
Run Code Online (Sandbox Code Playgroud)
选择随机:
select * from quest order by RANDOM();
| id | quest | resp_id |
3 128/1 24
1 1024/4 6
2 256/2 12
--
Run Code Online (Sandbox Code Playgroud)*每次选择时,订单都会有所不同.
如果您只想返回一行
select * from quest order by RANDOM() LIMIT 1;
| id | quest | resp_id |
2 256/2 12
--
Run Code Online (Sandbox Code Playgroud)*每次选择时,退货都会有所不同.
Sve*_*lov 12
SELECT bar
FROM foo
ORDER BY Random()
LIMIT 1
Run Code Online (Sandbox Code Playgroud)
这是@ank解决方案的修改:
SELECT *
FROM table
LIMIT 1
OFFSET ABS(RANDOM()) % MAX((SELECT COUNT(*) FROM table), 1)
Run Code Online (Sandbox Code Playgroud)
该解决方案也适用于带有间隙的索引,因为我们将偏移量随机化在[0,count)范围内。MAX
用于处理空表的情况。
以下是对具有16k行的表的简单测试结果:
sqlite> .timer on
sqlite> select count(*) from payment;
16049
Run Time: real 0.000 user 0.000140 sys 0.000117
sqlite> select payment_id from payment limit 1 offset abs(random()) % (select count(*) from payment);
14746
Run Time: real 0.002 user 0.000899 sys 0.000132
sqlite> select payment_id from payment limit 1 offset abs(random()) % (select count(*) from payment);
12486
Run Time: real 0.001 user 0.000952 sys 0.000103
sqlite> select payment_id from payment order by random() limit 1;
3134
Run Time: real 0.015 user 0.014022 sys 0.000309
sqlite> select payment_id from payment order by random() limit 1;
9407
Run Time: real 0.018 user 0.013757 sys 0.000208
Run Code Online (Sandbox Code Playgroud)