Tetapkan nilai acak dari set

11

Saya perlu memasukkan beberapa nilai acak ke dalam basis data, tetapi saya tidak ingin berakhir dengan teks yang benar-benar acak (seperti 7hfg43d3). Sebaliknya saya ingin memilih secara acak salah satu nilai yang disediakan oleh saya sendiri.

korda
sumber

Jawaban:

26

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;

-> SQLfiddle

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)]
Erwin Brandstetter
sumber
ceil (0) == lantai (0) +1?
korda
@korda: Saya menambahkan lebih banyak, mengatasinya.
Erwin Brandstetter
@ ErwinBrandstetter tidakkah Anda berpikir itu ceil(random())::intakan selalu memberi Anda 1 sehingga Anda tidak akan dapat memeriksa apakah itu akan kembali 0?
aki92
@ aki92: ceil(0.0)tidak akan, itu intinya. OTOH: untuk tujuan tes ini kita mungkin menyederhanakan: WHERE random() = 0.0.
Erwin Brandstetter
@ ErwinBrandstetter oh benar, maaf hanya melewatkan hal itu.
aki92
8

Saya datang dengan ide untuk menggunakan Array untuk mencapai ini:

(ARRAY['Foo','Bar','Poo'])[floor(random()*3)+1]
korda
sumber
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;

juanra
sumber
Anda dapat mengubah fungsi ini menjadi fungsi dengan parameter variadic yang menurut saya pribadi lebih ramah pengguna.
Sahap Asci