Ustaw losową wartość z zestawu

11

Muszę umieścić jakieś losowe wartości w bazie danych, ale nie chcę kończyć całkowicie losowym tekstem (np. 7hfg43d3). Zamiast tego chciałbym losowo wybrać jedną z wartości dostarczonych przez siebie.

korda
źródło

Odpowiedzi:

26

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;

-> SQLfiddle

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)]
Erwin Brandstetter
źródło
Ceil (0) == Floor (0) + 1?
korda,
@korda: Dodałem więcej, zajmując się tym.
Erwin Brandstetter,
@ErwinBrandstetter, nie sądzisz, że ceil(random())::intzawsze da ci 1, więc nie będziesz w stanie sprawdzić, czy kiedykolwiek zwróci 0?
aki92
@ aki92: ceil(0.0)nie, właśnie o to chodzi. OTOH: dla celów tego badania możemy uprościć: WHERE random() = 0.0.
Erwin Brandstetter,
@ErwinBrandstetter oh prawda, przepraszam, właśnie tęskniłem.
aki92
8

Wpadłem na pomysł użycia tablic, aby to osiągnąć:

(ARRAY['Foo','Bar','Poo'])[floor(random()*3)+1]
korda
źródło
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;

juanra
źródło
Możesz przekształcić tę funkcję w funkcję z parametrem variadic , który osobiście uważam za bardziej przyjazny dla użytkownika.
Sahap Asci