Establecer un valor aleatorio del conjunto

11

Necesito poner algunos valores aleatorios en la base de datos, pero no quiero terminar con un texto completamente aleatorio (como 7hfg43d3). En cambio, me gustaría elegir aleatoriamente uno de los valores proporcionados por mí mismo.

korda
fuente

Respuestas:

26

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;

-> SQLfiddle

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)]
Erwin Brandstetter
fuente
ceil (0) == piso (0) + 1?
korda
@korda: agregué más, abordando eso.
Erwin Brandstetter
@ErwinBrandstetter, ¿no crees que ceil(random())::inteso siempre te dará 1, por lo que no podrás comprobar si alguna vez devolverá 0?
aki92
@ aki92: ceil(0.0)no, ese es el punto. Otoh: el propósito de esta prueba que podríamos simplificar: WHERE random() = 0.0.
Erwin Brandstetter
@ErwinBrandstetter oh cierto, lo siento, acabo de perder esa cosa.
aki92
8

Se me ocurrió la idea de utilizar matrices para lograr esto:

(ARRAY['Foo','Bar','Poo'])[floor(random()*3)+1]
korda
fuente
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;

juanra
fuente
Puede transformar esta función en una función con parámetro variable que personalmente considero más fácil de usar.
Sahap Asci