Odpowiedzi:
Dobry pomysł. Proponuję dwa niewielkie uproszczenia:
('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
Prostsza składnia za pomocą literału tablicowego ( '{Foo,Bar,Poo}'::text[]
) Skraca ciąg dla dłuższych list. Dodatkowa korzyść: wyraźna deklaracja typu działa dla każdego typu, nie tylko dla text
. Twój oryginalny pomysł jest generowany text
, ponieważ jest to domyślny typ literałów łańcuchowych.
Użyj ceil()
zamiast floor() + 1
. Ten sam wynik.
OK, teoretycznie, dolna granica może wynosić dokładnie 0, jak wskazano w komentarzu , ponieważ random()
tworzy ( cytując tutaj instrukcję ):
wartość losowa w zakresie 0,0 <= x <1,0
Jednak nigdy tego nie widziałem. Przeprowadź kilka milionów testów:
SELECT count(*)
FROM generate_series(1,1000000)
WHERE ceil(random())::int = 0;
Aby być całkowicie bezpiecznym, możesz użyć niestandardowych indeksów tablic Postgres i nadal unikać dodatkowego dodawania:
('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]
Szczegóły dotyczące tego powiązanego pytania dotyczącego SO.
Lub jeszcze lepiej, użyj trunc()
, to trochę szybciej.
('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
ceil(random())::int
zawsze da ci 1, więc nie będziesz w stanie sprawdzić, czy kiedykolwiek zwróci 0?
ceil(0.0)
nie, właśnie o to chodzi. OTOH: dla celów tego badania możemy uprościć: WHERE random() = 0.0
.
W oparciu o ten pomysł stworzyłem funkcję, która była dla mnie bardzo przydatna:
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;
Przykłady użycia:
SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;
SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;