Yanıtlar:
İyi fikir. İki küçük basitleştirme öneriyorum:
('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
Değişmez dizi kullanarak daha basit sözdizimi ( '{Foo,Bar,Poo}'::text[]
) Dizeyi daha uzun listeler için kısaltır. Ek fayda: açık tür bildirimi, sadece tür için değil, her tür için çalışır text
. Orijinal fikriniz çıktı alır text
, çünkü bu dizi değişmezleri için varsayılan türdür.
Yerine ceil()
kullanın floor() + 1
. Aynı sonuç.
Tamam, teorik olarak, alt kenarlık , yorumunuzda ima edildiği gibi, tam olarak 0 olabilir , çünkü random()
üretir ( burada kılavuzdan alıntı yapılır ):
0.0 <= x <1.0 aralığında rastgele değer
Ancak, bunun olduğunu hiç görmedim. Birkaç milyon test yapın:
SELECT count(*)
FROM generate_series(1,1000000)
WHERE ceil(random())::int = 0;
Bununla birlikte, mükemmel bir şekilde güvende olmak için Postgres özel dizi aboneliklerini kullanabilir ve yine de ek eklemeden kaçınabilirsiniz:
('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]
SO ile ilgili bu sorunun altındaki ayrıntılar.
Ya da daha iyisi, kullanın trunc()
, bu biraz daha hızlı.
('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
ceil(random())::int
her zaman 1 vereceğini düşünmüyor musunuz, böylece 0'a dönüp dönmeyeceğini kontrol edemeyeceksiniz mi?
ceil(0.0)
yapmazdım, mesele bu. Otoh: Bu testin amacı için biz basitleştirmek olabilir: WHERE random() = 0.0
.
Bu fikre dayanarak, benim için oldukça yararlı bir işlev oluşturdum:
CREATE OR REPLACE FUNCTION random_choice(
choices text[]
)
RETURNS text AS $$
DECLARE
size_ int;
BEGIN
size_ = array_length(choices, 1);
RETURN (choices)[floor(random()*size_)+1];
END
$$ LANGUAGE plpgsql;
Kullanım örnekleri:
SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;
SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;