Нужно ли указывать ON DELETE NO ACTION на моем внешнем ключе?

У меня есть следующий DDL, который я использую с SQL Server 2012:

CREATE TABLE Subject (
   [SubjectId] INT IDENTITY (1, 1) NOT NULL,
   [Name] NVARCHAR (50) Not NULL,
   CONSTRAINT [PK_Subject] PRIMARY KEY CLUSTERED ([SubjectId] ASC)
)           

CREATE TABLE Topic (
   [TopicId] INT IDENTITY (1, 1) NOT NULL,
   [Name] NVARCHAR (50) NOT NULL,
   [SubjectId] INT NOT NULL,
   CONSTRAINT [PK_Topic] PRIMARY KEY CLUSTERED ([TopicId] ASC)
)
ALTER TABLE [Topic] WITH CHECK ADD  CONSTRAINT [FK_TopicSubject] 
   FOREIGN KEY([SubjectId]) REFERENCES [Subject] ([SubjectId]) 
   ON DELETE NO ACTION

Что я хочу, так это для SQL Server, чтобы я не удалял родителя, если ссылка на этого родителя существует в дочернем? Например, я хочу удалить на subjectID = 3 в теме сбой, если есть дети с SubjectId 3.

Для этого я неясен и не могу найти ответ. Нужно ли добавлять "УДАЛИТЬ НЕТ ДЕЙСТВИЙ", или я просто не могу удалить эти три слова.

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

Ответ 1

На странице column_constraint на MSDN:

ВКЛ. УДАЛЕНИЕ {НЕТ ДЕЙСТВИЯ | КАСКАД | SET NULL | SET DEFAULT}

Определяет, какое действие происходит с строками в изменяющейся таблице, если эти строки имеют ссылочное отношение, и ссылочная строка удаляется из родительской таблицы. По умолчанию используется НЕТ ДЕЙСТВИЯ.

Итак, вы можете выбрать ON DELETE NO ACTION, если хотите, и он будет работать одинаково.

НЕТ ДЕЙСТВИЯ означает, что ничего не произойдет, когда вы удаляете из таблицы Subject в таблицу Topic. В этом случае, если в теме есть строка для заданного объекта SubjectId, вы не можете удалить ее, не нарушая ссылочную целостность, поэтому удаление будет отменено.

Больше от MSDN:

НЕТ ДЕЙСТВИЯ - SQL Server Database Engine вызывает ошибку, и удалить действие в строке родительской таблицы.

Ответ 2

Я собираюсь предложить вам, что, хотя вы можете пропустить действие без удаления, это может быть не в ваших интересах. Если это указано в определении таблицы, это может помешать кому-то позже добавить каскадное удаление, потому что они видели, что вы намереваетесь, чтобы этого не произошло. Это особенно верно, когда вы правильно script все объекты базы данных и помещаете их в исходный элемент управления, и обозреватель кода увидит, что есть разница и спросите, почему это произошло. Слишком часто люди слишком стремятся добавить к каскаду удаления и уничтожить данные, которые должны были быть сохранены (например, финансовые записи для клиента, который больше не действителен). Они делают это, потому что получают ошибку, которая не позволяет им удалять и просто хочет избавиться от нее, а не осознавать, что это избавляет их от массовой ошибки. По крайней мере, если в вашей таблице script есть код для удаления "Нет действий", будущие сопровождающие будут видеть, что это было намеренно, а не только, что вы забыли настроить каскадные удаления. Конечно, если ваша дБА не разрешает каскадные удаления (как многие из них не так и по уважительной причине!), Это не является потенциальной проблемой, но указание вашего намерения часто является хорошей вещью для ремонтопригодности.

Ответ 3

"УДАЛИТЬ НЕТ ДЕЙСТВИЙ" действует так же, как "УДАЛИТЬ".

Я согласен, что было бы полезно использовать его, чтобы прояснить мысли программиста о необходимых действиях при удалении "заголовка" и решил, что "заголовок" не следует удалять, если с ним связаны "строки". Однако я определяю свою базу данных в Visual Studio, и она отказывается обновлять изменение с "УДАЛИТЬ" на "УДАЛИТЬ НЕТ ДЕЙСТВИЙ". Это все еще "НА УДАЛЕНИИ", когда я обновляю его.

Ответ 4

Вы можете удалить ключевые слова (это значение по умолчанию)

ON DELETE NO ACTION

Было бы лучше указать эти действия

ON DELETE CASCADE

Здесь более подробная информация: http://msdn.microsoft.com/en-us/library/aa933119%28v=sql.80%29.aspx

Вам нужно написать триггер, чтобы убедиться, что дочерняя строка не удалена, поскольку я не думаю, что SQL Server имеет эту опцию ON DELETE RESTRICT