Продолжить после ошибки нарушения первичного ключа
Проблема заключается во вставке данных из промежуточной таблицы во время процедуры импорта.
Система унаследована мной по наследству, и на короткий срок, пока я разрабатываю что-то более подходящее, я хочу исправлять ошибки, чтобы избежать сбоя при передаче данных.
К сожалению, средство существует через другое приложение для создания записи в таблицу, которая называется CommReceipt. Ключ называется CR_Key . если это произойдет, то при выполнении автоматической подпрограммы для вставки, скажем, 1000 строк, которые нам нужно импортировать из другой системы (не из моей системы) с уже определенными значениями CR_Key, произойдет сбой.
На мой взгляд, у меня есть несколько вариантов, но все предложения будут оценены по мере продвижения вперед для лучшего решения этой проблемы (как долгосрочные, так и краткосрочные исправления).
Это часть плана по устранению функциональности в мошенническом приложении (но это устаревшая система, написанная на устаревшем незнакомом языке и может потребовать немного усилий)
Как мне бороться с нарушением первичного ключа. Можно ли продолжить, сообщив о нарушении, с которым нужно разобраться после запуска вставки данных.
ОБНОВЛЕНИЕ: Первичный ключ CR_Key также является идентификатором, есть ли способ удалить строки, которых не должно быть, и вставить строки, используя один и тот же идентификатор. Я предполагаю.... Я выключаю тождество, затем указываю уникальные значения в "пропущенных строках", это правдоподобно? Мне не нужно автоматически увеличивать идентификатор, процедура вставки имеет идентификаторы
Спасибо
5 ответов
Вы можете использовать вместо триггера вставки. Внутри триггера выполните вставку в таблицу, где ее не существует. CommReceipt.CR_Key = insert.CR_Key.
Create trigger T_CommReceiptInsteadOfInsert on CommReceipt
Instead of Insert
As
Begin
--Insert duplicate records into another table
Insert Into CommReceipt_Duplicates(CR_Key, ...)
Select CR_Key, ...
From inserted i
Where exists (select * from CommReceipt c Where c.CR_Key = i.CR_Key)
--Insert non duplicate records
Insert Into CommReceipt(CR_Key, ...)
Select CR_Key, ...
From inserted i
Where not exists (select * from CommReceipt c Where c.CR_Key = i.CR_Key)
End
Возможно, вы могли бы использовать триггер, чтобы убедиться, что вставка может быть выполнена (ПК не существует). Если PK уже существует, вы можете сохранить некоторую информацию в другой таблице в виде журнала и отменить вставку, сделав откат и запустив исключение.
Во-первых, я предполагаю, что столкновения PK являются случайными, и что вновь вставленные строки действительно являются независимыми объектами (в отличие от чего-то, что должно было быть лучше обработано UPDATE
, Во-вторых, я предполагаю, что вы не можете отбросить этот первичный ключ и обработать столкновения "ключа" с заданием, выполняющимся после пакетной вставки (или вообще использовать альтернативный первичный ключ).
У вас есть несколько вариантов, если вы используете identity
в столбце первичного ключа (в этом случае ваше устаревшее приложение должно обходить идентификацию с помощью IDENTITY INSERT
для его успешных рядов):
Вы можете создать новую таблицу с той же схемой, что и CommReceipt, и поместить
INSTEAD OF
триггер на этой таблице, извлекая первичный ключ и вставляя в CommReceipt. Затем настройте устаревшее приложение, чтобы вставить его в эту новую таблицу.Вы можете отрегулировать начальное число идентификаторов в таблице CommReceipt для некоторого огромного числа вне диапазона мошеннических ключей устаревшего приложения. Это следует рассматривать как краткосрочное решение.
Если вы не используете идентификационные данные, то я предполагаю, что вы получаете значения PK из какой-то другой логики, к которой у устаревшего приложения нет доступа. Если это так, то у вас нет другого выбора, кроме как исправить устаревшее приложение или использовать независимое хранилище данных для его строк.
Нарушение ограничения PK является серьезной ошибкой в sqlserver, который в соответствии с BOL для sqlserver 2000 является уровнем 14, поэтому не считается фатальным, однако это немного похоже на систему проб / ошибок: уровень серьезности ошибки диктует, что будет sqlserver делать с проводимой транзакцией: если уровень серьезности достаточно высок, он прервет транзакцию на уровне сервера, и вы можете только перезапустить ее с самого начала.
Мое предложение было бы изменить внешнюю процедуру импорта так, чтобы она исключала внешне сгенерированный ключ CR_key и просто использовала тот же автоматически сгенерированный ключ, который используют все остальные.
Возможно, вам придется искажать вещи, чтобы получить этот результат. Например, вам может потребоваться выполнить внешний ввод в промежуточную таблицу, а затем использовать триггер для вставки в реальную таблицу, за исключением ключа CR_, который вы отбросите.
Существуют последствия для таких действий, и они могут быть отрицательными, в зависимости от требований. В общем случае не будет никакой связи между данными вашей основной таблицы и остальными данными в прежней системе. Если кто-то пытается выполнить внутреннее соединение между базами данных, он подвергается грубому шоку. Мне их жаль, но не очень.
Там может быть некоторая информация внутри CR_key. Это плохой дизайн ПК, но это случается, особенно в устаревших системах.
Удачи.