【发布时间】:2012-12-27 06:25:27
【问题描述】:
如何声明具有两个或三个值的变量数组,并在执行期间随机获取它们?
a := [1, 2, 5] -- sample sake
select random(a) -- returns random value
有什么建议从哪里开始吗?
【问题讨论】:
标签: arrays postgresql random plpgsql postgresql-9.2
如何声明具有两个或三个值的变量数组,并在执行期间随机获取它们?
a := [1, 2, 5] -- sample sake
select random(a) -- returns random value
有什么建议从哪里开始吗?
【问题讨论】:
标签: arrays postgresql random plpgsql postgresql-9.2
CREATE FUNCTION random_pick()
RETURNS int AS
$func$
DECLARE
a int[] := '{[0:2]=1,2,5}'; -- sample sake
BEGIN
RETURN a[floor((random()*3))::int];
END
$func$ LANGUAGE plpgsql VOLATILE
random() 返回一个值 x,其中 0.0 <= x < 1.0。乘以三和floor() 得到0、1 或2,机会均等。对于以1 开头的默认数组索引,这将是一对一的。为了提高效率,我将数组索引声明为以0 开头。
【讨论】:
Erwin Brandstetter answered the OP's question 足够好了。然而,对于其他想了解如何从更复杂的数组中随机选择元素的人(比如两个月前的我),我扩展了他的功能:
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;
几个假设:
这不仅适用于整数数组,也适用于任何类型的数组
我们忽略 NULL 数据;仅当数组为空或插入 NULL 时才返回 NULL(其他非数组类型的值产生错误)
数组不需要像往常一样格式化 - 数组索引可以在任何地方开始和结束,可能有间隙等。
这是一维数组
其他说明:
如果没有第一个IF 语句,空数组会导致无限循环
如果没有循环,间隙和 NULL 会使函数返回 NULL
如果您知道数组从零开始,请忽略两个 array_lower 调用
如果索引中有空白,您将需要array_upper 而不是array_length;没有间隙,是一样的(不确定哪个更快,但应该差别不大)
第二个array_lower 之后的+1 用于以与任何其他相同的概率获取数组中的最后一个值;否则它需要random() 的输出正好为 1,这永远不会发生
这比 Erwin 的解决方案要慢得多,并且可能会超出您的需求;在实践中,大多数人会从两者中混合一种理想的鸡尾酒
【讨论】:
array_length?
NULL 值的数组出现无限循环。可能想做a := ARRAY(SELECT x FROM unnest(a) AS rel(x) WHERE x NOT NULL)之类的事情。
CREATE FUNCTION random_pick(p_items anyarray)
RETURNS anyelement AS
$$
SELECT unnest(p_items) ORDER BY RANDOM() LIMIT 1;
$$ LANGUAGE SQL;
【讨论】:
这是做同样事情的另一种方法
WITH arr AS (
SELECT '{1, 2, 5}'::INT[] a
)
SELECT a[1 + floor((random() * array_length(a, 1)))::int] FROM arr;
您可以将数组更改为您想要的任何类型。
【讨论】:
试试这个:
select (array['Yes', 'No', 'Maybe'])[floor(random() * 3 + 1)];
【讨论】:
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;
对于更大的数据集,请参阅:
【讨论】:
width_bucket的粉丝,所以我的版本有RETURN vals[width_bucket(random(), 0, 1, array_length(vals, 1))];,但其他的都是一样的。