9

我需要在plpgsql中生成一个非重复随机数的随机数。非重复数应在[1,1001]范围内。但是,代码生成的数字超过 1001。

directed2number := trunc(Random()*7+1);
counter := directed2number
while counter > 0
loop
to_point := trunc((random() * 1/directed2number - counter/directed2number + 1) * 1001 +1);
...
...
counter := counter - 1;
end loop;
4

2 回答 2

4

如果我理解正确

  • 您需要一个随机数(1 到 8)的随机数。
  • 随机数范围为 1 到 1001
  • 随机数必须是唯一的。任何人不得出现超过一次。

CREATE OR REPLACE FUNCTION x.unique_rand_1001()
RETURNS SETOF integer AS
$body$
DECLARE
    nrnr    int := trunc(random()*7+1);  -- number of numbers
BEGIN

    RETURN QUERY
    SELECT (1000 * random())::integer + 1
    FROM   generate_series(1, nrnr*2)
    GROUP  BY 1
    LIMIT  nrnr;

END;
$body$ LANGUAGE plpgsql VOLATILE;

称呼:

SELECT x.unique_rand_1001();

数字由GROUP BY. 我生成的数字是需要的两倍,以提供足够的数字,以防删除重复项。对于给定的任务维度(1001 个数字中的最多 8 个),从天文角度来看,剩余的数字不太可能。最坏的情况:返回观众人数。

于 2011-11-30T03:44:34.627 回答
2

我不会在 PostgreSQL 中那样处理这个问题。

从软件工程的角度来看,我想我会在 x 和 y 之间单独生成一个随机整数,生成这些整数的“n”,并保证结果是一个集合。

-- Returns a random integer in the interval [n, m].
-- Not rigorously tested. For rigorous testing, see Knuth, TAOCP vol 2.
CREATE OR REPLACE FUNCTION random_integer(integer, integer)
  RETURNS integer AS
$BODY$
   select cast(floor(random()*($2 - $1 +1)) + $1 as integer);
$BODY$
  LANGUAGE sql VOLATILE

然后选择 1 到 1000 之间的单个随机整数,

select random_integer(1, 1000);

要选择 1 到 1000 之间的 100 个随机整数,

select random_integer(1, 1000)
from generate_series(1,100);

您可以保证应用程序代码或数据库中的唯一性。Ruby 实现了一个Set类。其他语言以各种名称具有类似的功能。

在数据库中执行此操作的一种方法是使用本地临时表。Erwin 关于需要生成比您需要的更多的整数以补偿删除重复项的需求是正确的。此代码生成 20,并按插入顺序选择前 8 行。

create local temp table unique_integers (
    id serial primary key,
    n integer unique
);

insert into unique_integers (n)
select random_integer(1, 1001) n
from generate_series(1, 20)
on conflict (n) do nothing;

select n 
from unique_integers
order by id
fetch first 8 rows only;
于 2011-11-29T18:39:39.297 回答