Câu trả lời:
Ý kiến hay. Tôi đề nghị hai đơn giản hóa nhỏ:
('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
Cú pháp đơn giản hơn bằng cách sử dụng một mảng bằng chữ ( '{Foo,Bar,Poo}'::text[]
) Rút ngắn chuỗi cho danh sách dài hơn. Lợi ích bổ sung: khai báo kiểu rõ ràng hoạt động cho bất kỳ loại nào, không chỉ cho text
. Ý tưởng ban đầu của bạn xảy ra với đầu ra text
, bởi vì đó là loại mặc định cho chuỗi ký tự.
Sử dụng ceil()
thay vì floor() + 1
. Cùng một kết quả.
OK, về mặt lý thuyết, đường viền dưới có thể là 0 chính xác, như được gợi ý trong nhận xét của bạn , kể từ khi random()
sản xuất ( trích dẫn hướng dẫn ở đây ):
giá trị ngẫu nhiên trong phạm vi 0,0 <= x <1,0
Tuy nhiên, tôi chưa bao giờ thấy điều đó xảy ra. Chạy một vài triệu bài kiểm tra:
SELECT count(*)
FROM generate_series(1,1000000)
WHERE ceil(random())::int = 0;
Tuy nhiên, để hoàn toàn an toàn, bạn có thể sử dụng các đăng ký mảng tùy chỉnh của Postgres và vẫn tránh bổ sung thêm:
('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]
Chi tiết theo câu hỏi liên quan này trên SO.
Hoặc tốt hơn, sử dụng trunc()
, đó là một chút nhanh hơn.
('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
ceil(random())::int
sẽ luôn cung cấp cho bạn 1 vì vậy bạn sẽ không thể kiểm tra xem nó có trở về 0 không?
ceil(0.0)
sẽ không, đó là điểm chính. OTOH: cho mục đích thử nghiệm này, chúng tôi có thể đơn giản hóa : WHERE random() = 0.0
.
Dựa trên ý tưởng này, tôi đã tạo ra một chức năng khá hữu ích cho tôi:
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;
Ví dụ sử dụng:
SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;
SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;