【问题标题】:ORDER BY random() with seed in SQLITEORDER BY random() 与 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,我在问题中提到过。正如我所提到的,我没有得到解决方案。

标签: php ios objective-c sqlite random


【解决方案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
    猜你喜欢
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-13
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    相关资源
    最近更新 更多