Risposte:
Bella idea Suggerisco due semplificazioni minori:
('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
Sintassi più semplice usando un array letterale ( '{Foo,Bar,Poo}'::text[]
) Accorcia la stringa per elenchi più lunghi. Vantaggio aggiuntivo: la dichiarazione esplicita del tipo funziona per qualsiasi tipo, non solo per text
. L'idea originale viene riprodotta text
, perché è il tipo predefinito per i letterali di stringa.
Usa ceil()
invece di floor() + 1
. Stesso risultato
OK, teoricamente, il bordo inferiore potrebbe essere esattamente 0, come suggerito nel tuo commento , poiché random()
produce ( citando il manuale qui ):
valore casuale nell'intervallo 0.0 <= x <1.0
Tuttavia, non l'ho mai visto accadere. Esegui un paio di milioni di test:
SELECT count(*)
FROM generate_series(1,1000000)
WHERE ceil(random())::int = 0;
Per essere perfettamente al sicuro, tuttavia, è possibile utilizzare gli abbonamenti di array personalizzati di Postgres ed evitare comunque l'aggiunta aggiuntiva:
('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]
Dettagli sotto questa domanda correlata su SO.
O meglio ancora, usa trunc()
, è un po 'più veloce.
('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
ceil(random())::int
ti darà sempre 1, quindi non sarai in grado di verificare se restituirà mai 0?
ceil(0.0)
no, questo è il punto. OTOH: Ai fini di questo test potremmo semplificare: WHERE random() = 0.0
.
Sulla base di questa idea, ho creato una funzione che mi è stata molto utile:
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;
Esempi di utilizzo:
SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;
SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;