Réponses:
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;
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)]
ceil(random())::intvous donnera toujours 1 donc vous ne pourrez pas vérifier s'il retournera jamais 0?
ceil(0.0)ne serait pas, c'est le point. OTOH: dans le but de ce test , nous pourrions simplifier: WHERE random() = 0.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;