如何声明一个具有两个或三个值的数组变量,并在执行过程中随机获取它们?
a := [1, 2, 5] -- sample sake
select random(a) -- returns random value
有什么建议从哪里开始吗?
试试这个:
select (array['Yes', 'No', 'Maybe'])[floor(random() * 3 + 1)];
CREATE OR REPLACE FUNCTION random_pick()
RETURNS int
LANGUAGE sql VOLATILE PARALLEL SAFE AS
$func$
SELECT ('[0:2]={1,2,5}'::int[])[trunc(random() * 3)::int];
$func$;
random()
返回值 x
,其中 0.0 <= x < 1.0
。乘以 3
,然后用 trunc()
截断(比 floor()
稍快),以 完全相等的机会得到
0
、1
或 2
。
Postgres 索引默认从 1 开始(根据 SQL 标准)。这将减少 1。我们可以每次加 1,或者声明数组索引以
0
开头。还快一点。参见:
PARALLEL SAFE
适用于 Postgres 9.6 或更高版本。参见:
如果您不想创建函数,可以使用简单的
SELECT
语句:
SELECT ('[0:2]={1,2,5}'::int[])[trunc(random() * 3)::int];
Erwin Brandstetter 很好地回答了OP 的问题。然而,对于其他想要了解如何从更复杂的数组中随机选取元素的人(比如两个月前的我),我扩展了他的功能:
CREATE OR REPLACE FUNCTION random_pick( a anyarray, OUT x anyelement )
RETURNS anyelement AS
$func$
BEGIN
IF a = '{}' THEN
x := NULL::TEXT;
ELSE
WHILE x IS NULL LOOP
x := a[floor(array_lower(a, 1) + (random()*( array_upper(a, 1) - array_lower(a, 1)+1) ) )::int];
END LOOP;
END IF;
END
$func$ LANGUAGE plpgsql VOLATILE RETURNS NULL ON NULL INPUT;
一些假设:
IF
语句,空数组将导致无限循环
array_lower
调用
array_upper
而不是
array_length
;没有间隙,它是相同的(不确定哪个更快,但它们应该没有太大不同)第二个
+1
array_lower
用于以与任何其他值相同的概率获取数组中的最后一个值;否则需要
random()
的输出恰好为 1,而这种情况永远不会发生
WITH arr AS (
SELECT '{1, 2, 5}'::INT[] a
)
SELECT a[1 + floor((random() * array_length(a, 1)))::int] FROM arr;
您可以将数组更改为您想要的任何类型。
CREATE OR REPLACE FUNCTION pick_random( members anyarray )
RETURNS anyelement AS
$$
BEGIN
RETURN members[trunc(random() * array_length(members, 1) + 1)];
END
$$ LANGUAGE plpgsql VOLATILE;
或
CREATE OR REPLACE FUNCTION pick_random( members anyarray )
RETURNS anyelement AS
$$
SELECT (array_agg(m1 order by random()))[1]
FROM unnest(members) m1;
$$ LANGUAGE SQL VOLATILE;
对于更大的数据集,请参阅:
CREATE FUNCTION random_pick(p_items anyarray)
RETURNS anyelement AS
$$
SELECT unnest(p_items) ORDER BY RANDOM() LIMIT 1;
$$ LANGUAGE SQL;