2009-11-16 2 views
4

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

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

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

+1

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

+0

См. Ответ Matt Ball для дубликатов. –

ответ

2

Multiply один с достаточно высоким значением

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

+0

К сожалению, я делаю это в T-SQL и у меня нет оператора с битрейтом. – abeger

+4

Тогда поддельные, что мать с умножением. :-) Я ДУМАЮ, что «key1 * 2^32» выполняет то же самое, но моя математика немного ржавая. – BlairHippo

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 для функции связывания Кантора! – azheglov

+0

Довольно сложный. Эти ответы потеряли меня в «биективном». : p – Kzqai

+0

@Tchalvak: если вы не очень похожий на математику, просто держите википедии в понятиях, которые вы не знаете! (Лично мне очень нравится «воспитывать» себя с таким производительным промедлением.) Это сводится к довольно простым вещам; использование причудливых математических слов просто держит определения краткими и точными. –

0

В Рискуя шутливой:

NewKey = fn(OldKey1, OldKey2) 

где п() является функцией, которая выглядит новый autonumbered ключ значение из столбца, добавленного в существующую таблицу.

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

2

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

combined = key2 * up1 + key1; 

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

+0

Мне нравится, чище, чем мой ответ был. Просто убедитесь, что вы всегда «кодируете» ключи в предопределенных порядках и «декодируете» их обратно в том же порядке. – Kzqai

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) для установки нового идентификатора? Они ДЕЙСТВИТЕЛЬНО должны быть в отношениях?

1

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

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

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

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

1

написал их для MySQL они прекрасно работают

CREATE FUNCTION pair (х BIGINT без знака, у BIGINT без знака) ВОЗВРАТ BIGINT неподписанный DETERMINISTIC RETURN ((х + у) * (х + у + 1))/2 + y;

CREATE FUNCTION reversePairX (г BIGINT без знака) ВОЗВРАТ BIGINT беззнаковое DETERMINISTIC RETURN (ПОЛ ((- 1 + SQRT (1 + 8 * г))/2)) * ((ПОЛ ((- 1 + SQRT (1 + 8 * z))/2)) + 3)/2 - z;

CREATE FUNCTION reversePairY (г BIGINT без знака) ВОЗВРАТ BIGINT беззнаковое DETERMINISTIC RETURN г - (ПОЛ ((- 1 + SQRT (1 + 8 * г))/2)) * ((ПОЛ ((- 1 + SQRT (1 + 8 * z))/2)) + 1)/2;

Смежные вопросы