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