Создайте уникальный первичный ключ (хэш) из столбцов базы данных

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

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

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

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

Или что-то типа того. Но это SQL.

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

Моя таблица имеет 3 номера и дату.

EDIT Что моя проблема

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

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

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

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

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

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

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

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

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

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

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

EDIT 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 

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

Что я буду делать дальше, удалите их все из целевого db, а затем просто вставьте их все s из моего db в целевую таблицу

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

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

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

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

 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

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

Предполагая, что вы обеспечили уникальность … вы можете сделать почти то же самое в 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, чтобы заполнить новое поле. Просто используйте левую часть логики условия объединения для значения.

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

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

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