Продолжить после ошибки нарушения первичного ключа

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

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

К сожалению, средство существует через другое приложение для создания записи в таблицу, которая называется 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. Это плохой дизайн ПК, но это случается, особенно в устаревших системах.

Удачи.

Другие вопросы по тегам