MySQL: получить случайный уникальный целочисленный идентификатор
Я попытался написать SQL-функцию, которая генерирует неиспользуемый уникальный идентификатор в диапазоне от 1000000 до 4294967295. Мне нужны числовые значения, поэтому UUID() не является решением. Это не кажется сложным, но по какой-то причине приведенный ниже код не работает, когда вызывается внутри оператора INSERT для таблицы в качестве значения для первичного ключа (конечно, не auto_increment). Утверждение как INSERT INTO table (id, content) VALUES ((SELECT getRandomID(0,0)), 'blabla bla');
(Так как значения по умолчанию не разрешены в таких функциях, я в скором времени отправляю 0 для каждого аргумента и устанавливаю в функции желаемое значение.)
Вызывается один раз и отделяется от INSERT или Python-кода, все хорошо. Вызывается несколько раз, происходит что-то странное, и не только весь процесс, но и сервер может зависнуть REPEAT
, Процесс тогда даже невозможно убить / перезапустить; Я должен перезагрузить компьютер -.- Кажется, у меня есть только некоторые случайные значения, готовые для меня, так как одни и те же значения появляются снова и снова после некоторых вызовов, хотя я и думал, что внутренние rand()
будет достаточным началом / семенем для внешнего rand()
, Вызванный из Python, цикл начинает зависать после нескольких раундов, хотя самый первый в моих тестах всегда дает полезный новый идентификатор и поэтому должен завершиться после первого раунда. Wyh? Ну, стол пуст... так SELECT COUNT(*)...
возвращает 0, что на самом деле является сигналом для выхода из цикла... но это не так.
Есть идеи? Я бегу MariaDB 10. что-то на SLES 12.2. Вот экспортированный исходный код:
DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `getRandomID`(`rangeStart` BIGINT UNSIGNED, `rangeEnd` BIGINT UNSIGNED) RETURNS bigint(20) unsigned
READS SQL DATA
BEGIN
DECLARE rnd BIGINT unsigned;
DECLARE i BIGINT unsigned;
IF rangeStart is null OR rangeStart < 1 THEN
SET rangeStart = 1000000;
END IF;
IF rangeEnd is null OR rangeEnd < 1 THEN
SET rangeEnd = 4294967295;
END IF;
SET i = 0;
r: REPEAT
SET rnd = FLOOR(rangeStart + RAND(RAND(FLOOR(1 + rand() * 1000000000))*10) * (rangeEnd - rangeStart));
SELECT COUNT(*) INTO i FROM `table` WHERE `id` = rnd;
UNTIL i = 0 END REPEAT r;
RETURN rnd;
END$$
DELIMITER ;
1 ответ
Небольшое улучшение:
SELECT COUNT(*) INTO i FROM `table` WHERE `id` = rnd;
UNTIL i = 0 END REPEAT r;
->
UNTIL NOT EXISTS( SELECT 1 FROM `table` WHERE id = rnd ) REPEAT r;
Не передавайте никаких аргументов RAND
- это для установления повторяющейся последовательности случайных чисел.
mysql> SELECT RAND(123), RAND(123), RAND(), RAND()\G
*************************** 1. row ***************************
RAND(123): 0.9277428611440052
RAND(123): 0.9277428611440052
RAND(): 0.5645420109522921
RAND(): 0.12561983719991504
1 row in set (0.00 sec)
Так упростить до
SET rnd = FLOOR(rangeStart + RAND() * (rangeEnd - rangeStart));
Если вы хотите включить rangeEnd
в возможных выходах добавьте 1:
SET rnd = FLOOR(rangeStart + RAND() * (rangeEnd - rangeStart + 1));