Подтвердить что ты не робот

ORDER BY random() с семенем в SQLITE

Я хотел бы реализовать пейджинг для случайного набора

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

Я попытался установить int на некоторое целое число и на некоторый перелом. Не работает

Как я могу выделить случайное число в sqlite?

Я использую шанс здесь с пустым голосом, потому что аналогичный вопрос уже существует - Посещение SQLite RANDOM(). Я просто не получил php-решение.

4b9b3361

Ответ 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 unit test просто используют memcpy() в глобальной структуре sqlite3Prng для сохранения или восстановления состояния PRNG во время тестовых прогонов.

Итак, если вы не хотите делать что-то странное (например, создайте временную таблицу последовательных чисел (1..max(Animals)), перетасуйте их вокруг и используйте их для выбора "случайных семян" RowIds из ваших животных таблица) Я полагаю, вам не повезло.

Ответ 2

Обычно я не копировал существующий ответ, но я вижу, что вы оставили комментарий, прося автора этого ответа, чтобы объяснить, как он работает уже несколько недель назад, и никаких объяснений не было. Поэтому я скопирую соответствующую часть и попытаюсь объяснить, что происходит. Если это объяснение является хорошим, пойдите и проголосуйте за исходный ответ.

$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. Затем строки сортируются в соответствии с десятичной частью полученного продукта. Используя меньшее число десятичных знаков, порядок сортировки будет выглядеть примерно так:

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

В этом примере я использовал только восемь строк, поэтому результат не очень случайный. С большим количеством строк результат будет казаться более случайным.

Это решение даст вам тот же порядок, если:

  • Вы используете одно и то же семя
  • В таблице нет новых строк, и ни одна строка не удалена из таблицы.

Ответ 3

Я не знаю, хотите ли вы PHP и iOS-решение, но если вас интересует только iOS и не интересует использование встроенной функции sqlite random(), вы можете объявить пользовательскую функцию используйте в своих запросах тот, который принимает параметр seed.

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

Ответ 4

Я использую это для случайного из семени в своей 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);
}