Respuestas:
Buena idea. Sugiero dos simplificaciones menores:
('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
Sintaxis más simple usando una matriz literal ( '{Foo,Bar,Poo}'::text[]) Acorta la cadena para listas más largas. Beneficio adicional: la declaración de tipo explícita funciona para cualquier tipo, no solo para text. Su idea original sucede con la salida text, porque ese es el tipo predeterminado para los literales de cadena.
Usar en ceil()lugar de floor() + 1. Mismo resultado.
OK, teóricamente, el borde inferior podría ser 0 con precisión, como se insinuó en su comentario , ya que random()produce ( citando el manual aquí ):
valor aleatorio en el rango 0.0 <= x <1.0
Sin embargo, nunca he visto que eso suceda. Ejecute un par de millones de pruebas:
SELECT count(*)
FROM generate_series(1,1000000)
WHERE ceil(random())::int = 0;
Sin embargo, para estar perfectamente seguro, puede usar subíndices de matriz personalizada de Postgres y aún así evitar la adición adicional:
('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]
Detalles bajo esta pregunta relacionada sobre SO.
O mejor aún, use trunc(), eso es un poco más rápido.
('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
ceil(random())::inteso siempre te dará 1, por lo que no podrás comprobar si alguna vez devolverá 0?
ceil(0.0)no, ese es el punto. Otoh: el propósito de esta prueba que podríamos simplificar: WHERE random() = 0.0.
Basado en esta idea, he creado una función que me fue bastante útil:
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;
Ejemplos de uso:
SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;
SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;