Заполнить переменную только при первом вызове функции postgresql
Есть функция, возвращающая таблицу. При вызове функции создается переменная-массив, которую необходимо заполнить случайными числами. Затем возвращается таблица с числами из переменной. Так вот, как сделать так, чтобы заполнение происходило только при первом обращении к функции? При последующих должны возвращаться те же самые значения, а не каждый раз генерироваться новые.
CREATE OR REPLACE FUNCTION fnc_generate_goods()
RETURNS TABLE (good VARCHAR, price INT) AS $$
BEGIN
FOR i IN 1..20 LOOP
RETURN QUERY(SELECT ('товар' || to_char(i, 'FM00'))::VARCHAR, i);
END LOOP;
END;
$$ LANGUAGE plpgsql;
Хочу рандомно сгенерировать цену для товаров, но чтобы она не менялась каждый раз при обращении к этой функции. Конечно, это можно сделать просто создав новую таблицу, но по заданию так нельзя...
Ответы (1 шт):
Если инициализировать random каждый раз одни и тем же числом, то цены будут случайные, но воспроизводимые между вызовами, если передавать seed в параметрах (захардкодить в функции тоже можно).
Но этот подход имеет серьёзный недостаток - все вызовы random() после вызова этой функции тоже будут воспроизводиться, поэтому использовать стоит только для учебных заданий или в сценариях тестирования. Добавил восстановление случайной последовательности.
CREATE OR REPLACE FUNCTION fnc_generate_goods(price_seed float)
RETURNS TABLE (good VARCHAR, price INT) AS $$
declare
previous_seed float;
BEGIN
select random() into previous_seed; -- remember current sequence
perform setseed(price_seed); -- generate expected sequence
FOR i IN 1..5 LOOP
RETURN QUERY(SELECT ('товар' || to_char(i, 'FM00'))::VARCHAR, (random()*1000)::int);
END LOOP;
perform setseed(previous_seed*2 - 1.0); -- restore sequence
END;
$$ LANGUAGE plpgsql;
Ниже вызовы fnc_generate_goods(0.43) и fnc_generate_goods(0.44) генерируют воспроизводимые цены, при этом вызовы random() за пределами fnc_generate_goods продолжают давать случайные числа.
postgres=# select * from fnc_generate_goods(0.43);
good | price
---------+-------
B>20@01 | 155
B>20@02 | 16
B>20@03 | 853
B>20@04 | 745
B>20@05 | 753
(5 rows)
postgres=# select random();
random
--------------------
0.4382084077869095
(1 row)
postgres=# select * from fnc_generate_goods(0.44);
good | price
---------+-------
B>20@01 | 740
B>20@02 | 736
B>20@03 | 845
B>20@04 | 614
B>20@05 | 977
(5 rows)
postgres=# select random();
random
-------------------
0.918940566300332
(1 row)
postgres=# select * from fnc_generate_goods(0.43);
good | price
---------+-------
B>20@01 | 155
B>20@02 | 16
B>20@03 | 853
B>20@04 | 745
B>20@05 | 753
(5 rows)
postgres=# select random();
random
--------------------
0.7218863495340173
(1 row)
postgres=# select * from fnc_generate_goods(0.44);
good | price
---------+-------
B>20@01 | 740
B>20@02 | 736
B>20@03 | 845
B>20@04 | 614
B>20@05 | 977
(5 rows)
postgres=# select random();
random
--------------------
0.5467171552940719
(1 row)