PostgreSQL PL/pgSQL值数组中的随机值

dly7yett  于 2023-01-13  发布在  PostgreSQL
关注(0)|答案(6)|浏览(263)

我怎样才能声明一个像数组一样有两个或三个值的变量,并在执行过程中随机得到它们?

a := [1, 2, 5] -- sample sake
select random(a) -- returns random value

有什么建议吗?

mf98qq94

mf98qq941#

试试这个:

select (array['Yes', 'No', 'Maybe'])[floor(random() * 3 + 1)];
8ftvxx2r

8ftvxx2r2#

更新于2023-01-10,修复了损坏的数组文字。使其在使用时速度提高了几倍:

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()稍快),以获得012,且 * 几率完全相等 *。
Postgres索引默认从1开始(根据SQL标准)。这将是一个差1。我们可以每次递增1,但为了提高效率,我声明数组索引从0开始。但稍微快一点。请参见:

PARALLEL SAFE适用于Postgres 9.6或更高版本。请参见:

如果不想创建函数,可以使用普通的SELECT语句:

SELECT ('[0:2]={1,2,5}'::int[])[trunc(random() * 3)::int];
3gtaxfhh

3gtaxfhh3#

然而,对于其他想了解如何从更复杂的数组中随机选取元素的人(就像两个月前的我),我扩展了他的函数:

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的解决方案要慢得多,而且可能会超出您的需求;实际上,大多数人会将两者混合成理想的鸡尾酒
fnx2tebb

fnx2tebb4#

下面是执行相同操作的另一种方法

WITH arr AS (
    SELECT '{1, 2, 5}'::INT[] a
)
SELECT a[1 + floor((random() * array_length(a, 1)))::int] FROM arr;

您可以将数组更改为所需的任何类型。

jtw3ybtb

jtw3ybtb5#

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;

对于更大的数据集,请参见:

fbcarpbf

fbcarpbf6#

CREATE FUNCTION random_pick(p_items anyarray)
RETURNS anyelement AS
$$
   SELECT unnest(p_items) ORDER BY RANDOM() LIMIT 1;
$$ LANGUAGE SQL;

相关问题