7

由于与问题不太相关的各种原因,我有一个表,其中包含由两个整数组成的复合键,我想从这两个数字中创建一个唯一键。我最初的想法是把它们连接起来,但是当我意识到 (51,1) 的复合键会产生与 (5,11) 相同的唯一键,即 511 时,我很快遇到了问题。

有没有人有聪明的方法从两个整数中生成一个整数,使得生成的整数对于一对起始整数是唯一的?

编辑:在面对大量数学之后,我意识到我应该包括的一个细节是相关键的大小。在原始对中,第一个密钥当前为 6 位,并且可能在系统生命周期内保持 7 位;第二个密钥尚未超过 20。鉴于这些限制,看起来问题不那么令人生畏了。

4

9 回答 9

22

如果您希望生成的密钥包含与其两个组件相同的位数,您可以在数学上证明这是不可能的。但是,如果您从两个 32 位 int 开始,并且可以使用 64 位 int 作为结果,您显然可以执行以下操作:

key1 << 32 | key2

SQL 语法

SELECT key1 * POWER(2, 32) + key2
于 2009-11-16T21:46:08.800 回答
5

已经对此进行了相当详细的讨论(正如递归所说,但是,输出必须包含比单个输入更多的位)。

以独特且确定的方式将两个整数映射为一个

如何使用两个数字作为 Map 键

http://en.wikipedia.org/wiki/Cantor_pairing_function#Cantor_pairing_function

于 2009-11-16T21:52:51.967 回答
2

因为我喜欢你问题的理论方面(它真的很漂亮),并且与许多实际答案所说的相矛盾,我想回答你标签的“数学”部分:)

事实上,可以将任意两个数字(或实际上是任何一系列数字)映射到一个数字。这被称为哥德尔数,由库尔特·哥德尔于 1931 年首​​次发表。

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

当然,得到的数字 v3 可能会增长得过快。请将此答案作为对您问题中理论方面的回答。

于 2009-11-19T16:51:59.277 回答
2

只有当您有一个键的上限时,您才能执行此操作。假设你有key1and key2, andup1是一个key1永远不会达到的值,那么你可以像这样组合键:

combined = key2 * up1 + key1;

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

于 2009-11-16T21:54:30.883 回答
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)
于 2009-11-16T21:57:52.557 回答
1

为mysql写了这些,它们工作正常

CREATE FUNCTION pair(x BIGINT unsigned, y BIGINT unsigned) RETURNS BIGINT unsigned DETERMINISTIC RETURN ((x + y) * (x + y + 1)) / 2 + y;

CREATE FUNCTION reversePairX(z BIGINT unsigned) RETURNS BIGINT unsigned DETERMINISTIC RETURN (FLOOR((-1 + SQRT(1 + 8 * z))/2)) * ((FLOOR((-1 + SQRT(1 + 8 * z))) /2)) + 3) / 2 - z;

CREATE FUNCTION reversePairY(z BIGINT unsigned) RETURNS BIGINT unsigned DETERMINISTIC RETURN z - (FLOOR((-1 + SQRT(1 + 8 * z))/2)) * ((FLOOR((-1 + SQRT(1 + 8 * z) ))/2)) + 1) / 2;

于 2013-11-05T20:25:52.100 回答
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

此方法也适用于任意数量的键。

于 2009-11-16T22:03:12.423 回答
0

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

于 2009-11-17T11:45:09.610 回答
0

冒着听起来很滑稽的风险:

NewKey = fn(OldKey1, OldKey2)

其中 fn() 是一个从添加到现有表的列中查找新的自动编号键值的函数。

显然,两个整数字段可以比单个整数字段保存指数更多的值。

于 2009-11-16T21:54:27.887 回答