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));
Другие вопросы по тегам