ORDER BY random() с семенем в SQLITE
Я хотел бы реализовать пейджинг для случайного набора
Select * from Animals ORDER BY random(SEED) LIMIT 100 OFFSET 50
Я попытался установить int на некоторое целое число и на некоторый перелом. Не работает
Как я могу выделить случайное число в sqlite?
Я использую шанс здесь с пустым голосом, потому что аналогичный вопрос уже существует - Посещение SQLite RANDOM(). Я просто не получил php-решение.
Ответы
Ответ 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);
}