在Postgresql中生成具有固定长度

时间:2015-11-17 15:24:18

标签: postgresql random

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

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

有可能吗?如果从前面的零开始是不可能的不是一个大问题(我认为),我可以在从数据库读取时以编程方式设置它们,但如果Postgresql可以自己完成它将会很棒。

- 编辑 -

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

我需要在Postgresql中生成唯一的随机数(bigint),其最大长度为13位。实际上我正在尝试使用pseudo_encrypt函数(64位),但返回的数字显然没有固定的最大长度为13,在32位情况下,最大长度为10位(int),并且64位是19(bigint)。

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

是否可以修改64位pseudo_ecrypt函数以获得此结果?或者,如果不可能,还有其他方法可以获得具有此要求的唯一序列吗?

伪加密功能(64位)

CREATE OR REPLACE FUNCTION pseudo_encrypt(VALUE bigint) returns bigint   AS $$
DECLARE
l1 bigint;
l2 bigint;
r1 bigint;
r2 bigint;
i int:=0;
BEGIN
l1:= (VALUE >> 32) & 4294967295::bigint;
r1:= VALUE & 4294967295;
WHILE i < 3 LOOP
    l2 := r1;
    r2 := l1 # ((((1366.0 * r1 + 150889) % 714025) / 714025.0) * 32767*32767)::int;
    l1 := l2;
    r1 := r2;
    i := i + 1;
END LOOP;
RETURN ((l1::bigint << 32) + r1);
END;
$$ LANGUAGE plpgsql strict immutable;

1 个答案:

答案 0 :(得分:11)

调整现有函数N&lt; 64位值

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

要获得13位小数,请考虑N有13位数的最大2^N。那个N = 42,2^42=4398046511104

该算法的工作原理是将输入值分成两半,位数相同,并使它们流过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;

输入必须小于(2^42)-1,否则输出会发生碰撞,如pseudo_encrypt42(x) = pseudo_encrypt42(x mod 2^42)

对于2 ^ 42和10 ^ 13之间缺少的数字可以做些什么?

2^42 - 10^13 = 5601953488896因此缺少相当多的数字。 我不知道如何通过Feistel网络一次性帮助解决这个问题。但是,可以接受的一种解决方法是在0..M中生成另一组唯一值并向其添加2^42,因此不存在冲突风险。

这个另一个集合可以通过相同的函数获得,只需添加偏移量即可。 4398046511104 + pseudo_encrypt42(x)保证在43980465111042*4398046511104 = 8796093022208个唯一值之间,以便更接近目标。相同的技术可以应用于其他几个范围,甚至不一定具有相同的范围。

然而,这种解决方法会降低随机行为,因为不是只有一个输出范围,而每个数字都在0X之间,你得N X/N个数字的不同输出范围。有了这样的几个不同的分区,很容易猜出输出的分区,而不是分区内的值。