php ORDER BY随机(),种子位于SQLITE中

0pizxfdo  于 2023-01-12  发布在  PHP
关注(0)|答案(4)|浏览(200)

我想对随机集实现分页

Select * from Animals ORDER BY random(SEED) LIMIT 100 OFFSET 50

我试着把int设成整数和fracture,没用.
如何在sqlite中随机播种?
我知道已经存在类似的问题Seeding SQLite RANDOM(),但我不理解PHP的解决方案。

niknxzdl

niknxzdl1#

简短答复:

SQLite的random()函数不支持种子值。

答案不短:

检查SQLite的func.c显示random()定义时没有任何参数。

VFUNCTION(random,            0, 0, 0, randomFunc       ),

..并且这个randomFunc()只调用sqlite3_randomity()(同样没有任何显式种子值)来获得 sizeof(sqlite_int64) 字节的随机值。
在内部,sqlite3_randomity()的实现(参见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表中选择“随机种子”RowId),否则我想你的运气不好。

a11xaf1n

a11xaf1n2#

我通常不会复制现有的答案,但我可以看到你已经留下了一个评论,要求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

在这个例子中,我只使用了八行,所以结果看起来不是很随机。更多的行,结果会显得更随机。
只要满足以下条件,此解决方案将重复为您提供相同的顺序:

  • 你用同样的种子
  • 表中未出现任何新行,也未从表中删除任何行
3hvapo4f

3hvapo4f3#

我不知道您是否需要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
ffvjumwh

ffvjumwh4#

我在我的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);
}

相关问题