2009-11-16 61 views
4

由于各种原因与问题没有太大关系,我得到了一个由两个整数组成的组合键的表格,我想从这两个数字中创建一个唯一的键。我最初的想法是将它们连接起来,但当我意识到(51,1)的组合键将导致与(5,11)相同的唯一键,即511时,我迅速遇到了问题。是否有一种简单的方法来从两个整数组合键创建唯一的整数键?

有没有人有一种巧妙的方法来从两个整数中生成一个整数,这样生成的整数对于这对起始整数是唯一的?

编辑:在遇到大量的数学问题之后,我意识到我应该包含的一个细节是有问题的键的大小。在始发对中,第一个键目前是6位数字,并且在系统的整个生命周期中可能会保持7位数字;第二个关键还没有超过20个。鉴于这些限制,看起来这个问题不那么令人生畏。

+1

没有DBA应该让你摆脱这个 - 如果需要的话,创建一个primark密钥列并在两列上使用唯一约束 – 2009-11-16 21:53:40

+0

请参阅Matt Ball的重复答案 – 2009-11-16 22:00:32

回答

2

乘以一个足够高的值

SELECT id1 * 1000000 + id2 

或者使用文本串联:

SELECT CAST(CAST(id1 AS nvarchar(10)) + RIGHT('000000' + CAST(id2 AS nvarchar(10)), 6) AS int) 

或跳过整数事情和标识的东西非数字分开:

SELECT CAST(id1 AS nvarchar) + ':' + CAST(id2 AS nvarchar) 
20

如果您希望得到的密钥包含与其两个组件相同数量的位,您可以从数学上证明这是不可能的。但是,如果有两个32位的整数开始,可以使用64位的int的结果,你可以明显地做这样的事情:

key1 << 32 | key2 
+0

这个。当然,确保你在这两个整数中加入了理智检查,以确保它们都是32位。 (假设你使用带符号整数,它们需要小于2^31或2,147,483,648)。 – BlairHippo 2009-11-16 21:51:26

+0

不幸的是,我在T-SQL中这样做并且缺少一个移位操作符。 – abeger 2009-11-16 21:59:02

+4

然后假装乘法的母亲。 :-)我认为“key1 * 2^32”完成同样的事情,但我的数学有点生疏。 – BlairHippo 2009-11-16 22:03:28

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

+0

+1对于Cantor配对功能! – azheglov 2009-11-16 22:13:00

+0

相当复杂。这些答案让我失去了“双眼”。 :p – Kzqai 2009-11-16 22:15:02

+0

@Tchalvak:如果你不是一个数学的人,只需保持维基百科的条款你不知道! (就我个人而言,我真的很喜欢用那种高效的拖延来“教育”自己。)它归结为非常简单的东西;使用花哨的数学词汇只是使定义简明扼要。 – 2009-11-16 22:48:20

0

在冠冕堂皇的风险开玩笑:

NewKey = fn(OldKey1, OldKey2) 

其中,fn()是从查找新autonumbered键值的功能列添加到您现有的表。

很明显,两个整数字段可以比一个整数字段指数多地保存值。

2

如果您有一个密钥的上限,则只能这样做。假设你有key1key2,并up1是一个值,key1将永远无法达到,那么你可以结合键是这样的:

combined = key2 * up1 + key1; 

即使密钥理论上成长无极限,它通常是可以估计在实践中保存上限。

+0

我喜欢,比我的回答更干净。只需要确保您始终按照预定义的顺序对这些键进行“编码”,并按照相同的顺序将它们“解码”。 – Kzqai 2009-11-16 22:22:11

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

此方法还概括为任何数量的键。

0

为什么不使用ROW_NUMBER()或IDENTITY(int,1,1)来设置新的ID?他们真的需要关系吗?

1

因为我喜欢你的问题的理论方面(它真的很漂亮),并且与许多实际答案中的内容相抵触,所以我想回答一下你的标签中的“数学”部分:)

事实上,有可能将任何两个数字(或实际上任何系列的数字)映射到一个数字。这被称为Gödel number,并于1931年由KurtGödel首次发表。

举个简单的例子,用你的问题;假设我们有两个变量v1和v2。然后v3 = 2 v1 * 3 v2会给出一个唯一的数字。该数字还唯一标识v1和v2。

当然,得到的数字v3可能会快速增长,不合需要。请把这个答案作为对你问题理论方面的回答。

1

写这些为MySQL它们很好地工作

CREATE FUNCTION pair(X BIGINT无符号,Y BIGINT无符号) RETURNS BIGINT无符号DETERMINISTIC RETURN((X + Y)*(X + Y + 1))/ 2 + y;

CREATE FUNCTION reversePairX(Z BIGINT无符号) RETURNS BIGINT无符号DETERMINISTIC RETURN(FLOOR(( - 1 + SQRT(1个+ 8 * Z))/ 2))*((FLOOR(( - 1 + SQRT( 1 + 8 * z))/ 2))+ 3)/ 2-z;

CREATE FUNCTION reversePairY(Z BIGINT无符号) RETURNS BIGINT无符号DETERMINISTIC RETURNž - (FLOOR(( - 1 + SQRT(1 + 8 * Z))/ 2))*((FLOOR(( - 1 + SQRT(1 + 8 * z))/ 2))+ 1)/ 2;

相关问题