Définir une valeur aléatoire à partir de l'ensemble

11

J'ai besoin de mettre des valeurs aléatoires dans la base de données, mais je ne veux pas me retrouver avec du texte complètement aléatoire (comme 7hfg43d3). Au lieu de cela, je voudrais choisir au hasard l'une des valeurs fournies par moi-même.

korda
la source

Réponses:

26

Bonne idée. Je suggère deux simplifications mineures:

('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
  • Syntaxe plus simple utilisant un tableau literal ( '{Foo,Bar,Poo}'::text[]) Raccourcit la chaîne pour les listes plus longues. Avantage supplémentaire: la déclaration de type explicite fonctionne pour tout type, pas seulement pour text. Votre idée d'origine se produit en sortie text, car c'est le type par défaut pour les littéraux de chaîne.

  • Utilisez ceil()au lieu de floor() + 1. Même résultat.

OK, théoriquement, la bordure inférieure pourrait être 0 précisément, comme l'indique votre commentaire , car random()produit (en citant le manuel ici ):

valeur aléatoire dans la plage 0,0 <= x <1,0

Cependant, je n'ai jamais vu cela se produire. Exécutez quelques millions de tests:

SELECT count(*)
FROM   generate_series(1,1000000)
WHERE  ceil(random())::int = 0;

-> SQLfiddle

Cependant, pour être parfaitement sûr, vous pouvez utiliser des indices de tableau personnalisés Postgres et éviter l'ajout supplémentaire:

('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]

Détails sous cette question connexe sur SO.

Ou mieux encore, utilisez trunc(), c'est un peu plus rapide.

('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
Erwin Brandstetter
la source
plafond (0) == étage (0) + 1?
korda
@korda: J'en ai ajouté plus en abordant cela.
Erwin Brandstetter
@ErwinBrandstetter ne pensez-vous pas que cela ceil(random())::intvous donnera toujours 1 donc vous ne pourrez pas vérifier s'il retournera jamais 0?
aki92
@ aki92: ceil(0.0)ne serait pas, c'est le point. OTOH: dans le but de ce test , nous pourrions simplifier: WHERE random() = 0.0.
Erwin Brandstetter
@ErwinBrandstetter oh vrai, désolé d'avoir raté cette chose.
aki92
8

J'ai eu l'idée d'utiliser des tableaux pour accomplir cela:

(ARRAY['Foo','Bar','Poo'])[floor(random()*3)+1]
korda
la source
0

Sur la base de cette idée, j'ai créé une fonction qui m'a été très 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;

Exemples d'utilisation:

  • 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
la source
Vous pouvez transformer cette fonction en une fonction avec un paramètre variadique que je trouve personnellement plus convivial.
Sahap Asci