Здравствуйте. Подскажите пожалуйста, как лучше всего решить такую задачу? Есть поле в таблице 'serialNumber' STRING(9), и нужно при создании записи, сгененировать уникальное значение, которого нет в базе, размер поля 9 знаков, ну и возможные знаки - "0-9".
Как вариант конечно можно в триггере, в цикле создавать рандомное число, а потом делать выборку в таблице наличие этого числа, пока выборка не вернет пустую запись.
Но может есть лучшее решение?
П.С. Есть один нюанс числа не должны быть подряд, это будет что-то типа серийного номера для лицензии
Странно. История изменений говорит что вопрос не менялся. Значит это я прохлопал уточнение в постскриптум.
serialNumber именно serial, последовательный.
Спасибо за ответы. Ну у меня это что-то как когда-то были скретч-карты пополнения мобильных, где сгенерирован уникальный 16-значный код.
П.С. Немного подумав, у меня возник алгорит.
1) Создать таблицу serialNumber с одним полем serialNumber и последовательно заполнить эту таблицу всеми значениями (выйдет 1 миллиард значений, хотя в принципе диапазон можно уменьшить )
2) При создании новой записи в нужной таблицы триггером выбираем рандомную запись с таблицы serialNumber, вставляем ее в нужную таблицу, и удаляем ее с таблицы serialNumber.
Как бы операция будет довольно не частая, как будет по производительности не знаю.
Может более оптимальную идею подскажите?
Если я не промахнулся в расчётах, то 1млрд bigint - табличка размером порядка 30гб. Плюс pk где-то в половину этого размера.
Работать предварительно созданная табличка будет, работать будет хорошо если правильно реализовать поиск следующего значения даже на хорошем уровне concurrency. Только может быть немного жаль 50гб.
А если подходить объективно к задаче и потому рассчитывать на малое число коллизий:
with recursive s as (select (random() * 1e9)::bigint as n, 0 nested union all select (random() * 1e9)::bigint, nested+1 from s where nested < 1e6) select n from s where not exists (select from tablename where tablename.serialNumber = s.n) limit 1;
Уникальное ограничение по serialNumber всё равно нужно.
Melkij, Спасибо, думаю на первых нескольких миллионах записей все будет работать как надо, уже наверное последние числа будет непросто генерировать. Вот получилась такая функция
CREATE OR REPLACE FUNCTION public.cartridges_insert()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
IF NEW.balance = 0 and NEW.quantity != 0 THEN
NEW.balance := NEW.quantity;
END IF;
NEW.code := (WITH RECURSIVE serialNumber AS (
SELECT
LPAD((RANDOM() * 1e9)::bigint::character(9), 9, '0') AS code,
0 AS nested
UNION ALL
SELECT
LPAD((RANDOM() * 1e9)::bigint::character(9), 9, '0') AS code,
nested + 1 AS nested
FROM serialNumber where nested < 1e6
)
SELECT code FROM serialNumber
WHERE NOT EXISTS (
SELECT FROM "Cartridges" WHERE code = serialNumber.code
)
LIMIT 1
);
RETURN NEW;
END;
$function$
;