ORDER BY random() 与 SQLITE 中的种子
Posted
技术标签:
【中文标题】ORDER BY random() 与 SQLITE 中的种子【英文标题】:ORDER BY random() with seed in SQLITE 【发布时间】:2014-08-07 00:28:44 【问题描述】:我想为一个随机集合实现分页
Select * from Animals ORDER BY random(SEED) LIMIT 100 OFFSET 50
我尝试将 int 设置为某个整数和某个断点。没用
如何在 sqlite 中随机播种?
我在这里投了反对票,因为类似的问题已经存在 - Seeding SQLite RANDOM()。我只是没有得到php解决方案。
【问题讨论】:
在您的代码示例中,将SEED
设置为您选择的整数。例如,Select * from Animals ORDER BY random(9001) LIMIT 100 OFFSET 50
我试过了。它不起作用
你使用什么语言?
Seeding SQLite RANDOM()的可能重复
@chalup,我在问题中提到过。正如我所提到的,我没有得到解决方案。
【参考方案1】:
简答:
你不能。 SQLite 的 random() 函数不支持种子值。
不是那么简短的回答:
检查 SQLite 的 func.c 表明 random() 是在没有任何参数的情况下定义的。
VFUNCTION(random, 0, 0, 0, randomFunc ),
..这个 randomFunc() 只是调用 sqlite3_randomness() (同样没有任何明确的种子值)来获得 sizeof(sqlite_int64) 字节的随机值。
在内部,sqlite3_randomness() 的实现(参见random.c)将在第一次使用从操作系统获得的随机种子值时设置 RC4 伪随机数生成器:
/* Initialize the state of the random number generator once,
** the first time this routine is called. The seed value does
** not need to contain a lot of randomness since we are not
** trying to do secure encryption or anything like that...
**
** [..]
*/
if( !wsdPrng.isInit )
[..]
sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k);
[..]
wsdPrng.isInit = 1;
实际上,SQLite 的单元测试函数本身只是在全局 sqlite3Prng 结构上使用 memcpy() 来保存或恢复测试运行期间 PRNG 的状态。
所以,除非您愿意做一些奇怪的事情(例如创建一个包含连续数字的临时表 (1..max(Animals))),否则将它们随机排列并使用它们从您的 Animals 中选择“随机种子”RowIds表)我想你运气不好。
【讨论】:
怎么回事? mysql 有这个选项而 sqlite 没有? 当然,它们是完全不同的产品。两者都是使用 SQL 标准的关系数据库系统,但仅此而已。【参考方案2】:我不知道你是否想要一个 PHP 和 ios 解决方案,但如果你只对 iOS 感兴趣并且不太关心使用内置的 sqlite random() 函数,您可以声明一个自定义函数以在您的查询中使用,该函数采用种子参数。
sqlite3_create_function(database, "CUSTOM_RANDOM", 1, SQLITE_UTF8, NULL, &CustomRandomSQLite, NULL, NULL);
.
void CustomRandomSQLite(sqlite3_context* context, int argc, sqlite3_value** argv)
if(argc == 1 && sqlite3_value_type(argv[0]) == SQLITE_INTEGER)
const int seed = sqlite3_value_int(argv[0]);
const int result = ...;
sqlite3_result_int(context, result);
else
sqlite3_result_error(context, "Invalid", 0);
.
Select * from Animals ORDER BY CUSTOM_RANDOM(SEED) LIMIT 100 OFFSET 50
【讨论】:
这一行中的 ... 是什么意思: const int result = ...; 播种在哪里? ... 是代码的占位符,用于获取种子并将随机数返回到结果变量中 如果你只想要随机数,你也可以删除种子并用 0 个参数设置它,然后设置 int result = arc4random()【参考方案3】:我在我的 javascript 游戏中从种子中随机使用它,我相信你可以很容易地将它转换为 sql
seed: function(max)
if(typeof this._random === 'undefined') this._random = max; // init on first run
this._random = (this._random * 9301 + 49297) % 233280;
return Math.floor(this._random / (233280.0) * max);
【讨论】:
【参考方案4】:我通常不会复制现有答案,但我可以看到您在几周前发表评论要求this answer 的作者解释它是如何工作的,但没有给出任何解释。因此,我将复制相关部分并尝试解释发生了什么。如果这个解释很好,请对原始答案进行投票。
$seed = md5(mt_rand());
$prng = ('0.' . str_replace(array('0', 'a', 'b', 'c', 'd', 'e', 'f'), array('7', '3', '1', '5', '9', '8', '4'), $seed )) * 1;
$query = 'SELECT id, name FROM table ORDER BY (substr(id * ' . $prng . ', length(id) + 2)';
前两行只是关于创建某种种子。结果是一个带有很多小数的十进制数,例如:
0.54534238371923827955579364758491
然后sql select使用这个数字与SQLite
表中每一行的数字行id相乘。然后根据结果产品的小数部分对行进行排序。使用较少的小数,排序顺序如下所示:
row id row id * seed sort order
1 0.545342384 545342384
2 1.090684767 090684767
3 1.636027151 636027151
4 2.181369535 181369535
5 2.726711919 726711919
6 3.272054302 272054302
7 3.817396686 817396686
8 4.362739070 362739070
排序后会是这样的结果:
row id row id * seed sort order
2 1.090684767 090684767
4 2.181369535 181369535
6 3.272054302 272054302
8 4.362739070 362739070
1 0.545342384 545342384
3 1.636027151 636027151
5 2.726711919 726711919
7 3.817396686 817396686
在这个示例中,我只使用了八行,因此结果看起来不是很随机。行越多,结果就越随机。
只要:
你使用相同的种子 表中没有出现新行,也没有从表中删除任何行【讨论】:
您使用子字符串而不是“% 1”是否有原因? 那是因为 sqlite 讨厌小数。对十进制值使用 %1 会返回 0,而我无法使用 CAST 解决任何问题。我的解决方法很旧 (x * 1e7) % 1e7以上是关于ORDER BY random() 与 SQLITE 中的种子的主要内容,如果未能解决你的问题,请参考以下文章
SQLite Random() 在 ORDER BY 中没有正确排序
如何同时使用 DISTINCT 和 ORDER BY RANDOM 进行 SELECT?
对 Oracle 数据库使用 ORDER BY dbms_random.value 时的性能问题