由于与问题没有太大关系的各种原因,我有一个带有由两个整数组成的复合键的表,我想从这两个数字中创建一个唯一的键。我最初的想法只是将它们连接起来,但当我意识到(51,1)的复合键会产生与(5,11)相同的唯一键时,我很快就遇到了问题,即511.
有没有人有一种聪明的方法来生成两个整数中的整数,这样生成的整数对于这对起始整数是唯一的?
编辑在面对大量的数学后,我意识到我应该包含的一个细节是所讨论的密钥的大小。在始发对中,第一个密钥当前是6位数,并且在系统的生命周期中可能保持7位数;第二个关键还没有超过20个。鉴于这些限制,看起来问题就不那么令人生畏了。
答案 0 :(得分:21)
如果您希望生成的密钥包含与其两个组件相同的位数,则可以在数学上证明这是不可能的。但是,如果从两个32位整数开始,并且可以使用64位int作为结果,那么显然可以这样做:
key1 << 32 | key2
答案 1 :(得分:4)
已经在相当多的细节中对此进行了讨论(正如递归所说,输出必须包含比单个输入更多的位)。
Mapping two integers to one, in a unique and deterministic way
How to use two numbers as a Map key
http://en.wikipedia.org/wiki/Cantor_pairing_function#Cantor_pairing_function
答案 2 :(得分:2)
只有拥有其中一个键的上限时,才能执行此操作。假设您有key1
和key2
,而up1
是key1
永远不会达到的值,那么您可以将这些键组合起来:
combined = key2 * up1 + key1;
即使键理论上可以无限制地增长,通常也可以在实践中估计保存上限。
答案 3 :(得分:2)
将一个具有足够高的值乘以
SELECT id1 * 1000000 + id2
或使用文字连接:
SELECT CAST(CAST(id1 AS nvarchar(10)) + RIGHT('000000' + CAST(id2 AS nvarchar(10)), 6) AS int)
或者跳过整数并将ID与非数字分隔:
SELECT CAST(id1 AS nvarchar) + ':' + CAST(id2 AS nvarchar)
答案 4 :(得分:1)
这两个建议的解决方案都需要一些关于接受密钥范围的知识。
为避免做出这种假设,可以将数字混合在一起。
Key1 = ABC => Digits = A, B, C
Key2 = 123 => Digits = 1, 2, 3
Riffle(Key1, Key2) = A, 1, B, 2, C, 3
当没有足够的数字时,可以使用零填充:
Key1 = 12345, Key2 = 1 => 1020304051
此方法还可以推广任意数量的键。
答案 5 :(得分:1)
由于我喜欢你问题的理论方面(它真的很漂亮),并且与许多实际答案所说的相矛盾,我想回答你标签的“数学”部分:)
实际上可能将任意两个数字(或实际上任何数字系列)映射到一个数字。这被称为Gödel number,最初由KurtGödel于1931年出版。
用你的问题快速举例说明;说我们有两个变量v1和v2。然后v3 = 2 v1 * 3 v2 将给出唯一的数字。此编号还唯一标识v1和v2。
当然,得到的数字v3可能会不合需要地快速增长。请把这个答案作为对你问题中理论方面的回答。
答案 6 :(得分:1)
为mysql编写了这些可以正常工作的
CREATE FUNCTION pair
(x BIGINT unsigned,y BIGINT unsigned)
返回BIGINT无符号确定性
返回((x + y)*(x + y + 1))/ 2 + y;
CREATE FUNCTION reversePairX
(z BIGINT unsigned)
返回BIGINT无符号确定性
返回(FLOOR(( - 1 + SQRT(1 + 8 * z))/ 2))*((FLOOR(( - 1 + SQRT(1 + 8 * z))/ 2))+ 3)/ 2 - z ;
CREATE FUNCTION reversePairY
(z BIGINT unsigned)
返回BIGINT无符号确定性
返回z - (FLOOR(( - 1 + SQRT(1 + 8 * z))/ 2))*((FLOOR(( - 1 + SQRT(1 + 8 * z))/ 2))+ 1)/ 2 ;
答案 7 :(得分:0)
冒着听起来很滑稽的风险:
NewKey = fn(OldKey1, OldKey2)
其中fn()是一个函数,用于从添加到现有表中的列中查找新的自动编号键值。
显然,两个整数字段可以比单个整数字段保持指数多的值。
答案 8 :(得分:0)
为什么不直接使用ROW_NUMBER()或IDENTITY(int,1,1)来设置新ID?他们真的需要关系吗?