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

标签 postgresql random

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

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

这可能吗?如果不可能从前面的零开始不是一个大问题(我认为),我可以在从数据库读取期间以编程方式设置它们,但如果 Postgresql 可以自行完成,那就太好了。

-- 编辑--

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

我需要在 Postgresql 中生成最大长度固定为 13 位的唯一随机数 (bigint)。实际上我正在尝试使用 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;

最佳答案

为 N < 64 位值调整现有函数

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

要获得 13 位十进制数字,请考虑 2^N 有 13 位的最大 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 数字的不同输出范围。有了几个这样的不同分区,很容易猜测输出将在哪个分区中,而不是分区内的值。

关于postgresql - 在Postgresql中生成固定长度的唯一随机数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33760630/

相关文章:

c++ - 在二维 vector C++ 中生成随机数

javascript - 创建具有随机 0 和 1 值的矩阵的代码

objective-c - D std.random 整数和小数均匀随机数生成之间的不同行为

postgresql - NULL 和 NULL::character 在 PostgreSQL 中有什么区别

PostgreSQL 与子字符串比较不起作用

Python:我需要随机生成6个数字,它们的总和等于指定的数字

c++ - XCode C++ 程序没有运行正确的循环

sql - 从函数返回的记录具有连接的列

sql - postgres - 保留查询中的重复项

linux - 当数据库安装在无响应的文件系统上时,服务 postgresql 停止挂起 - 导致 ha 故障转移挂起