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())::int
eso 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;