Есть ли простой способ создать уникальный целочисленный ключ из составного ключа с двумя целыми числами? - PullRequest
5 голосов
/ 17 ноября 2009

По разным причинам, которые не слишком уместны для вопроса, у меня есть таблица с составным ключом, состоящим из двух целых чисел, и я хочу создать один уникальный ключ из этих двух чисел. Сначала я хотел просто объединить их, но быстро столкнулся с проблемой, когда понял, что составной ключ (51,1) приведет к тому же уникальному ключу, что и (5,11), а именно 511.

Есть ли у кого-нибудь умный способ сгенерировать целое число из двух целых чисел, чтобы сгенерированное целое число было уникальным для пары начальных целых чисел?

Редактировать: После того, как я столкнулся с впечатляющим количеством математики, я понял, что одна деталь, которую я должен был включить, - это размеры рассматриваемых клавиш. В исходной паре первый ключ в настоящее время состоит из 6 цифр и, вероятно, останется в 7 цифрах на весь срок службы системы; второй ключ еще должен быть больше 20. Учитывая эти ограничения, похоже, проблема гораздо менее устрашающая.

Ответы [ 9 ]

21 голосов
/ 17 ноября 2009

Вы можете математически доказать, что это невозможно, если вы хотите, чтобы результирующий ключ содержал то же число битов, что и его два компонента. Однако, если вы начинаете с двух 32-битных целочисленных значений и можете использовать для результата 64-битное целое число, вы, очевидно, можете сделать что-то вроде этого:

key1 << 32 | key2
4 голосов
/ 17 ноября 2009

Это уже обсуждалось довольно подробно (однако, как уже говорилось рекурсивно, выходные данные должны состоять из большего количества бит, чем отдельные входы).

Отображение двух целых в одно уникальным и детерминированным образом

Как использовать два числа в качестве ключа карты

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

2 голосов
/ 17 ноября 2009

Умножьте один на достаточно высокое значение

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)
2 голосов
/ 17 ноября 2009

Вы можете сделать это, только если у вас есть верхняя граница для одного из ключей. Допустим, у вас есть key1 и key2, а up1 - это значение, которое key1 никогда не достигнет, тогда вы можете комбинировать ключи следующим образом:

combined = key2 * up1 + key1;

Даже если теоретически ключи могут расти без ограничений, на практике обычно можно оценить верхнюю границу сохранения.

1 голос
/ 06 ноября 2013

написал их для mysql, они отлично работают

ФУНКЦИЯ СОЗДАТЬ pair (x BIGINT без знака, y BIGINT без знака) ВОЗВРАЩАЕТ BIGINT без знака ДЕТЕРМИНИСТИЧЕСКИЙ ВОЗВРАТ ((x + y) * (x + y + 1)) / 2 + y;

ФУНКЦИЯ СОЗДАТЬ reversePairX (z BIGINT без знака) ВОЗВРАЩАЕТ BIGINT без знака ДЕТЕРМИНИСТИЧЕСКИЙ ВОЗВРАТ (ЭТАЖ ((- 1 + SQRT (1 + 8 * z)) / 2)) * ((ЭТАЖ ((- 1 + SQRT (1 + 8 * z)) / 2)) + 3) / 2 - z ;

ФУНКЦИЯ СОЗДАТЬ reversePairY (z BIGINT без знака) ВОЗВРАЩАЕТ BIGINT без знака ДЕТЕРМИНИСТИЧЕСКИЙ ВОЗВРАТ z - (ЭТАЖ ((- 1 + SQRT (1 + 8 * z)) / 2)) * ((ЭТАЖ ((- 1 + SQRT (1 + 8 * z)) / 2)) + 1) / 2 ; * +1010 *

1 голос
/ 19 ноября 2009

Поскольку мне нравится теоретическая сторона вашего вопроса (это действительно красиво), и чтобы противоречить тому, что говорят многие практические ответы, я бы хотел дать ответ на "математическую" часть ваших тегов: *

Фактически возможно сопоставить любые два числа (или фактически любые серии чисел) с одним числом. Это называется число Геделя и впервые было опубликовано в 1931 году Куртом Геделем.

Чтобы привести быстрый пример, с вашим вопросом; скажем, у нас есть две переменные v1 и v2. Тогда v3 = 2 v1 * 3 v2 даст уникальный номер. Этот номер также однозначно идентифицирует v1 и v2.

Конечно, результирующее число v3 может расти нежелательно быстро. Пожалуйста, просто примите этот ответ как ответ на теоретический аспект вашего вопроса.

1 голос
/ 17 ноября 2009

Оба предложенных решения требуют определенных знаний о диапазоне принятых ключей.

Чтобы не делать этого предположения, можно смешать цифры вместе.

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 голосов
/ 17 ноября 2009

Почему бы вам просто не использовать ROW_NUMBER () или IDENTITY (int, 1,1) для установки нового идентификатора? Они ДЕЙСТВИТЕЛЬНО должны быть в отношениях?

0 голосов
/ 17 ноября 2009

С риском звучать шутливо:

NewKey = fn(OldKey1, OldKey2)

где fn () - это функция, которая ищет новое значение ключа с автонумерацией из столбца, добавленного в существующую таблицу.

Очевидно, что два целочисленных поля могут содержать экспоненциально больше значений, чем одно целочисленное поле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...