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 时的性能问题

order by 与group by 啥意思啊,数据库高手看看

UNION ALL、UNION与ORDER BY

Hive中的Order by与关系型数据库中的order by语句的异同点