Antworten:
Gute Idee. Ich schlage zwei kleinere Vereinfachungen vor:
('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
Einfachere Syntax mit einem Array-Literal ( '{Foo,Bar,Poo}'::text[]
) Verkürzt die Zeichenfolge für längere Listen. Zusätzlicher Vorteil: Die explizite Typdeklaration funktioniert für jeden Typ, nicht nur für text
. Ihre ursprüngliche Idee wird zufällig ausgegeben text
, da dies der Standardtyp für Zeichenfolgenliterale ist.
Verwenden Sie ceil()
anstelle von floor() + 1
. Gleiches Ergebnis.
OK, theoretisch könnte der untere Rand genau 0 sein, wie in Ihrem Kommentar angedeutet , da random()
erzeugt ( zitiert das Handbuch hier ):
Zufallswert im Bereich 0.0 <= x <1.0
Ich habe das jedoch noch nie gesehen. Führen Sie einige Millionen Tests durch:
SELECT count(*)
FROM generate_series(1,1000000)
WHERE ceil(random())::int = 0;
Um jedoch absolut sicher zu sein, können Sie benutzerdefinierte Array-Indizes von Postgres verwenden und dennoch die zusätzliche Hinzufügung vermeiden:
('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]
Details unter dieser verwandten Frage zu SO.
Oder noch besser, verwenden Sie trunc()
, das ist ein bisschen schneller.
('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
ceil(random())::int
du immer 1 bekommst, damit du nicht überprüfen kannst, ob es jemals 0 zurückgibt ?
ceil(0.0)
würde nicht, das ist der Punkt. OTOH: Für den Zweck dieses Tests könnten wir vereinfachen : WHERE random() = 0.0
.
Basierend auf dieser Idee habe ich eine Funktion erstellt, die für mich sehr nützlich war:
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;
Anwendungsbeispiele:
SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;
SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;