Jawaban:
Ide bagus. Saya menyarankan dua penyederhanaan kecil:
('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
Sintaks yang lebih sederhana menggunakan array literal ( '{Foo,Bar,Poo}'::text[]
) Mempersingkat string untuk daftar yang lebih panjang. Manfaat tambahan: deklarasi tipe eksplisit bekerja untuk semua jenis, bukan hanya untuk text
. Gagasan orisinal Anda terjadi pada keluaran text
, karena itulah tipe default untuk string literal.
Gunakan ceil()
sebagai ganti floor() + 1
. Hasil yang sama
OK, secara teoritis, batas bawah bisa 0 tepat, seperti yang ditunjukkan dalam komentar Anda , sejak random()
menghasilkan ( mengutip manual di sini ):
nilai acak dalam kisaran 0,0 <= x <1,0
Namun, saya belum pernah melihat itu terjadi. Jalankan beberapa juta tes:
SELECT count(*)
FROM generate_series(1,1000000)
WHERE ceil(random())::int = 0;
Agar aman sepenuhnya, Anda dapat menggunakan larik larik kustom Postgres dan masih menghindari penambahan tambahan:
('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]
Detail di bawah pertanyaan terkait ini di SO.
Atau lebih baik lagi, gunakan trunc()
, itu sedikit lebih cepat.
('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
ceil(random())::int
akan selalu memberi Anda 1 sehingga Anda tidak akan dapat memeriksa apakah itu akan kembali 0?
ceil(0.0)
tidak akan, itu intinya. OTOH: untuk tujuan tes ini kita mungkin menyederhanakan: WHERE random() = 0.0
.
Berdasarkan ide ini, saya telah membuat fungsi yang cukup berguna bagi saya:
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;
Contoh penggunaan:
SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;
SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;