在Postgresql中生成固定长度的唯一随机数

在Postgresql中生成固定长度的唯一随机数,postgresql,random,Postgresql,Random,我需要在Postgresql中生成固定长度为13位的唯一随机数。 我发现了一个类似的例子,其中使用了使用“pseudo_encrypt”加密的序列,但返回的数字不是固定长度的 所以,我需要的是:获取一个固定长度为13位的加密随机序列,其中最小值为0000000000001,最大值为9999999999 可能吗?如果从前面的零开始是不可能的,这不是一个大问题(我认为),我可以在从db读取的过程中以编程方式设置它们,但是如果Postgresql能够自己完成这项工作,那就太好了 --编辑-- 在意识到

我需要在Postgresql中生成固定长度为13位的唯一随机数。 我发现了一个类似的例子,其中使用了使用“pseudo_encrypt”加密的序列,但返回的数字不是固定长度的

所以,我需要的是:获取一个固定长度为13位的加密随机序列,其中最小值为0000000000001,最大值为9999999999

可能吗?如果从前面的零开始是不可能的,这不是一个大问题(我认为),我可以在从db读取的过程中以编程方式设置它们,但是如果Postgresql能够自己完成这项工作,那就太好了

--编辑--

在意识到一些有用的事情后,我必须改变问题,以便更好地解释我需要什么:

我需要在Postgresql中生成唯一随机数(bigint),最大固定长度为13位。实际上,我试图使用函数(64位),但返回的数字显然不是固定的最大长度13,在32位的情况下,最大长度是10位(int),而对于64位,最大长度是19位(bigint)

那么,如何获得一个固定最大长度为13位的加密随机序列,其中最小值为1,最大值为9999999999

是否可以修改64位伪加密函数以获得此结果?或者,如果不可能,是否有其他方法来获得符合此要求的唯一序列

伪加密函数(64位)

CREATE或REPLACE函数pseudo_encrypt(值bigint)将bigint返回为$$
声明
l1 bigint;
l2-bigint;
r1-bigint;
r2-bigint;
i int:=0;
开始
l1:=(值>>32)&4294967295::bigint;
r1:=值&4294967295;
当我<3圈时
l2:=r1;
r2:=l1#((1366.0*r1+150889)%714025)/714025.0)*32767*32767)::int;
l1:=l2;
r1:=r2;
i:=i+1;
端环;
RETURN((l1::bigint为N<64位值调整现有函数

调整bigint变量将输出减少到
2^N
值相对简单,其中
N
是偶数,小于64

获取13个十进制数字,考虑最大值<代码> n>代码>,其中<代码> 2 ^ n/COD>有13位数字,即n=42,<代码> 2 ^ 42=4398046511104 < /代码> ./P> 该算法的工作原理是将输入值分成两个具有相同位数的两半,并使它们流经Feistel网络,基本上是与轮函数的结果异或,并在每次迭代时交换两半

如果在该过程的每个阶段,每一半都被限制为
21
位,则组合两部分的结果保证不超过42位

下面是我建议的变体:

CREATE OR REPLACE FUNCTION pseudo_encrypt42(VALUE bigint) returns bigint
 AS $$
DECLARE
  l1 bigint;
  l2 bigint;
  r1 bigint;
  r2 bigint;
  i int:=0;
  b21 int:=(1<<21)-1; -- 21 bits mask for a half-number => 42 bits total
BEGIN
  l1:= VALUE >> 21;
  r1:= VALUE & b21;
  WHILE i < 3 LOOP
    l2 := r1;
    r2 := l1 # (((((1366*r1+150889)%714025)/714025.0)*32767*32767)::int & b21);
    l1 := l2;
    r1 := r2;
    i := i + 1;
  END LOOP;
  RETURN ((l1::bigint << 21) + r1);
END;
$$ LANGUAGE plpgsql strict immutable;
创建或替换函数pseudo_encrypt42(值bigint)返回bigint
作为$$
声明
l1 bigint;
l2-bigint;
r1-bigint;
r2-bigint;
i int:=0;
b21 int:=(1>21;
r1:=值&b21;
当我<3圈时
l2:=r1;
r2:=l1#(((((1366*r1+150889)%714025)/714025.0)*32767*32767)::int&b21);
l1:=l2;
r1:=r2;
i:=i+1;
端环;

RETURN((l1::bigint您可以将该函数返回的值格式化为具有固定长度:
到_char(pseudo_encrypt(nextval('seq')::int),'0000000000000')
那么序列呢?我必须如何设置它?与您链接的问题相同。只需确保您的最大值不超过13位。好的,我会尝试让您知道,谢谢!我可以第一个学究式地声明,如果值是唯一的,那么根据定义,它们也不能是随机的。谢谢。T他的解决了我的问题,谢谢丹尼尔!这是一个非常详细的回答,我相信这对其他开发人员也会非常有用!我认为在您的情况下,输入必须小于
(2^21)
,以避免冲突,因为您使用
值>>(64-21)
作为左侧部分(就像从左侧取21位)。在这种情况下,对于大于
2^21
且小于某个值的值,您仍然会得到0作为左半部分,但右半部分将再次从零开始。为了解决此问题,我使用
VALUE>>21
shift作为左半部分(就像在前21位之后取下一个21位),然后是您的限制
(2^42)
生效。@mopdobot:你说得对,很好。我在答案中修正了密码。
CREATE OR REPLACE FUNCTION pseudo_encrypt42(VALUE bigint) returns bigint
 AS $$
DECLARE
  l1 bigint;
  l2 bigint;
  r1 bigint;
  r2 bigint;
  i int:=0;
  b21 int:=(1<<21)-1; -- 21 bits mask for a half-number => 42 bits total
BEGIN
  l1:= VALUE >> 21;
  r1:= VALUE & b21;
  WHILE i < 3 LOOP
    l2 := r1;
    r2 := l1 # (((((1366*r1+150889)%714025)/714025.0)*32767*32767)::int & b21);
    l1 := l2;
    r1 := r2;
    i := i + 1;
  END LOOP;
  RETURN ((l1::bigint << 21) + r1);
END;
$$ LANGUAGE plpgsql strict immutable;