Создать уникальный первичный ключ (хеш) из столбцов базы данных - PullRequest
2 голосов
/ 25 августа 2009

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

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

Если бы это был язык программирования, подобный Java, я бы:

 int hash = column1 * 31 + column2 * 31 + column3*31 

Или что-то в этом роде. Но это SQL.

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

В моей таблице 3 числа и дата.

РЕДАКТИРОВАТЬ В чем моя проблема

Я думаю, что нужно немного больше фона. Извините, что не предоставил это раньше.

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

В прошлом месяце (июль) процесс обновления был прерван, и в течение месяца не было обновлений данных в dm.

Я вручную создаю таблицу с той же структурой в моем Oracle XE и копирую записи из исходного источника в свою базу данных (myxe). Я скопировал только записи с июля, чтобы создать отчет, необходимый к концу месяца.

Наконец, 8 августа процесс обновления был исправлен, и записи, ожидающие переноса этим автоматическим процессом, были скопированы в базу данных (из originalsource в dm).

Этот процесс очищает от исходного источника данные после их копирования (в dm).

Все выглядит хорошо, но мы только что поняли, что количество записей потеряно (около 25% июля)

Итак, я хочу использовать резервную копию (myxe) и вставить в базу данных (dm) все отсутствующие записи.

Проблема здесь:

  • У них нет четко определенного ПК.
  • Они находятся в отдельных базах данных.

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

РЕДАКТИРОВАТЬ 2

Итак, я сделал следующее в своей локальной среде:

select a.* from the_table@PRODUCTION a , the_table b where
a.idle = b.idle and 
a.activity = b.activity and 
a.finishdate = b.finishdate

Который возвращает все строки, которые присутствуют в обеих базах данных (.. union?) У меня есть 2000 записей.

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

Надеюсь, я не попаду в худшее: - S: -S

Ответы [ 4 ]

3 голосов
/ 25 августа 2009

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

Вместо этого я бы рекомендовал использовать автоинкрементный идентификатор для вашего первичного ключа.

3 голосов
/ 25 августа 2009

Просто создайте суррогатный ключ:

ALTER TABLE mytable ADD pk_col INT

UPDATE  mytable
SET     pk_col = rownum

ALTER TABLE mytable MODIFY pk_col INT NOT NULL

ALTER TABLE mytable ADD CONSTRAINT pk_mytable_pk_col PRIMARY KEY (pk_col)

или это:

ALTER TABLE mytable ADD pk_col RAW(16)

UPDATE  mytable
SET     pk_col = SYS_GUID()

ALTER TABLE mytable MODIFY pk_col RAW(16) NOT NULL

ALTER TABLE mytable ADD CONSTRAINT pk_mytable_pk_col PRIMARY KEY (pk_col)

Последний использует GUID, которые уникальны для разных баз данных, но занимают больше места и генерируются намного медленнее (ваши INSERT будут работать медленнее)

Обновление:

Если вам нужно создать одинаковые PRIMARY KEY s для двух таблиц с идентичными данными, используйте это:

MERGE
INTO    mytable v
USING   (
        SELECT  rowid AS rid, rownum AS rn
        FROM    mytable
        ORDER BY
                co1l, col2, col3
        )
ON      (v.rowid = rid)
WHEN MATCHED THEN
UPDATE
SET     pk_col = rn

Обратите внимание, что таблицы должны быть идентичны с точностью до одной строки (т. Е. Иметь одинаковое количество строк с одинаковыми данными в них).

Update 2

Для вашей самой проблемы вам вообще не нужно PK.

Если вы просто хотите выбрать записи, отсутствующие в dm, используйте эту (со стороны dm)

SELECT  *
FROM    mytable@myxe
MINUS
SELECT  *
FROM    mytable

Это вернет все записи, которые существуют в mytable@myxe, но не в mytable@dm

Обратите внимание, что все дубликаты будут уменьшены, если таковые имеются.

1 голос
/ 25 августа 2009

Если вы загружаете новую таблицу со значениями из старой таблицы, а затем вам необходимо объединить две таблицы, вы можете сделать это «правильно» только в том случае, если сможете однозначно идентифицировать каждую строку в исходной таблице. Решение Quassnoi позволит вам сделать это, ЕСЛИ вы можете сначала изменить старую таблицу, добавив новый столбец.

Если вы не можете изменить исходную таблицу, генерирование хеш-кода в некоторой форме на основе столбцов старой таблицы будет работать, но, опять же, только если хеш-коды однозначно идентифицируют каждую строку. (Oracle имеет функции контрольной суммы, верно? Если это так, используйте их.)

Если уникальность хеш-кода не может быть гарантирована, вам, возможно, придется согласиться на первичный ключ, состоящий из такого количества столбцов, которые необходимы для обеспечения уникальности (например, естественного ключа). Если нет естественного ключа, хорошо, я однажды услышал, что Oracle предоставляет rownum для каждой строки данных, вы могли бы использовать это?

1 голос
/ 25 августа 2009

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

Select Table2.SomeFields 
    FROM Table1 LEFT OUTER JOIN Table2 ON
        (Table1.col1 * 31) + (Table1.col2 * 31) + (Table1.col3 * 31) + 
            ((DatePart(year,Table1.date) + DatePart(month,Table1.date) + DatePart(day,Table1.date) )* 31) = Table2.hashedPk

Приведенный выше запрос будет работать для SQL Server, единственное отличие для Oracle будет в том, как вы обрабатываете преобразование даты. Более того, в SQL Server есть и другие функции для преобразования дат, так что это далеко не единственное решение.

И вы можете комбинировать это с оператором SET Quassnoi, чтобы также заполнить новое поле. Просто используйте левую часть логики условия соединения для значения.

...