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

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

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

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

Как я семя случайно в sqlite?

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

Короткий ответ:

Вы не можете. Функция random () SQLite не поддерживает начальное значение.

Не так короткий ответ:

Проверка func.c SQLite показывает, что random () определен без каких-либо параметров.

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

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

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

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

 $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 

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

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

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

Я не знаю, хотите ли вы решение 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 

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