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.

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)]

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]

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;


Anda dapat mengubah fungsi ini menjadi fungsi dengan parameter variadic yang menurut saya pribadi lebih ramah pengguna.
Sahap Asci
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.