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