Если вы повторно используете тот же список для delete, тогда вы можете подумать о том, чтобы вставить ключи для удаления во временную таблицу, а затем использовать это во втором запросе.
SELECT Key, ...
INTO #ToDelete
FROM Table T
WHERE ...
Затем что-то вроде этого
...
LEFT OUTER JOIN #ToDelete D
ON T.Key=D.Key
WHERE D.Key IS NULL
DROP #ToDelete
Если вы указали внешний ключ как ограничение при создании таблицы в базе данных, вы можете указать базе данных, что делать в случае удаления, установив правило удаления. Это правило определяет, что произойдет, если пользователь попытается удалить строку с данными, которые связаны с внешним ключом. Параметр «Нет действий» сообщает пользователю, что удаление запрещено, и выполняется откат DELETE. Реализация этого позволит вам не проверять его самостоятельно перед удалением, и, таким образом, может рассматриваться как своего рода попытка. Ну, по крайней мере, в MS SQL так работает. http://msdn.microsoft.com/en-us/library/ms177288.aspx
В терминах одной команды, которая проверяет отношения только один раз (а не дважды в вашем примере - один раз для НЕ СУЩЕСТВУЕТ
, один раз для DELETE
), то я ожидаю, что ответ будет большим жирным нет, извините.
(неуместная идея): Если это серьезная проблема, вы можете попробовать какую-нибудь реализацию подсчета ссылок, используя триггеры для обновления счетчика - но на самом деле я ожидаю, что это потребует гораздо больше накладных расходов, чем простая проверка ключей, как вы уже делаете.
Вы также можете исследовать NOCHECK
во время удаления (поскольку вы проверяете его сами); но вы можете сделать это только на уровне таблицы (так что, вероятно, нормально для сценариев администратора, но не для производственного кода) - то есть:
-- disable
alter table ChildTableName nocheck constraint ForeignKeyName
-- enable
alter table ChildTableName check constraint ForeignKeyName
Быстрый тест показывает, что при его включении выполняется дополнительное сканирование кластерного индекса для внешнего ключа; если он отключен, это опускается.
Вот полный пример; вы можете посмотреть план запроса для двух операций DELETE
... (в идеале изолированно от остального кода):
create table parent (id int primary key)
create table child (id int primary key, pid int)
alter table child add constraint fk_parent foreign key (pid)
references parent (id)
insert parent values (1)
insert parent values (2)
insert child values (1,1)
insert child values (2,1)
-- ******************* THIS ONE CHECKS THE FOREIGN KEY
delete from parent
where not exists (select 1 from child where pid = parent.id)
-- reset
delete from child
delete from parent
insert parent values (1)
insert parent values (2)
insert child values (1,1)
insert child values (2,1)
-- re-run with check disabled
alter table child nocheck constraint fk_parent
-- ******************* THIS ONE DOESN'T CHECK THE FOREIGN KEY
delete from parent
where not exists (select 1 from child where pid = parent.id)
-- re-enable
alter table child check constraint fk_parent
Опять же - я подчеркиваю, что это следует запускать только из таких вещей, как сценарии администратора .
Я нашел одну статью, в которой обсуждается использование внешнего соединения при удалении: http://www.bennadel.com/blog/939-Using-A-SQL-JOIN-In-A-SQL-DELETE-Statement-Thanks-Pinal-Dave-.htm
Надеюсь, это сработает для вас!
Вы можете создать индексированное представление выбранного предложения:
SELECT key FROM table WHERE table.key = centretable.key
Индексированное представление - это физическая копия данных, поэтому ее можно будет очень быстро проверить.
У вас есть накладные расходы на обновление представления, поэтому вам нужно будет проверить это в соответствии с вашим шаблоном использования.
Краткий ответ на ваш вопрос: нет, не существует стандартного ключевого слова СУБД для удаления главной записи, когда все ссылки на внешние ключи на нее исчезают (и, конечно, ни одна из них будет учитывать внешние ключи в нескольких таблицах).
Ваш наиболее эффективный вариант - это второй запрос, который запускается по мере необходимости для удаления из "центра" на основе серии предложений NOT EXISTS () для каждого из таблицы с внешними ключами.
Это основано на двух утверждениях, которые, как я считаю, верны для вашей ситуации:
Вы удалите больше «связанных» записей, чем «центральных» (родительских) записей. Таким образом, любая операция, которая пытается настроить «центр» каждый раз, когда вы удаляете из одной из других таблиц, приведет к мгновенному обновлению «центра», но потребует много напрасных запросов для удаления «центральной» записи только изредка.
Учитывая, что на звезде есть несколько точек от «центра», любые «потраченные впустую усилия» проверка внешнего ключа в одной из них минимальны по сравнению в целом. Например, если есть четыре внешних ключа, которые нужно проверить перед удалением из «центра», вы можете сэкономить, в лучшем случае, 25% времени.