Answers:
好主意。我建议进行两个较小的简化:
('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
使用数组文字('{Foo,Bar,Poo}'::text[]
)的语法更简单,可缩短字符串以获取更长的列表。附加好处:显式类型声明适用于任何类型,而不仅适用于text
。您最初的想法发生在output上text
,因为这是字符串文字的默认类型。
使用ceil()
代替floor() + 1
。结果相同。
好的,从理论上讲,下边界可以精确地为0,正如您的注释中所暗示的那样,因为random()
产生了(在此引用手册):
范围内的随机值0.0 <= x <1.0
但是,我从未见过这种情况。运行几百万个测试:
SELECT count(*)
FROM generate_series(1,1000000)
WHERE ceil(random())::int = 0;
不过,为了绝对安全,您可以使用Postgres自定义数组下标,并且仍然避免额外的添加:
('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]
('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]
ceil(random())::int
总是会给您1,所以您将无法检查它是否会返回0?
ceil(0.0)
不会,这就是重点。OTOH:为进行此测试,我们可以简化:WHERE random() = 0.0
。
基于这个想法,我创建了一个对我来说非常有用的函数:
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;
用法示例:
SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;
SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;