web-dev-qa-db-fra.com

Dois-je spécifier ON DELETE NO ACTION sur ma clé étrangère?

J'ai la DDL suivante que j'utilise avec 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

Ce que je veux, c'est que SQL Server m'empêche de supprimer un parent si une référence à ce parent existe dans l'enfant? Par exemple, je veux qu'une suppression sur subjectID = 3 dans Subject échoue s'il y a des enfants avec SubjectId de 3.

Pour cela, je ne suis pas clair et ne semble pas trouver la réponse. Dois-je ajouter "SUPPRIMER AUCUNE ACTION" ou puis-je simplement ne pas supprimer ces trois mots.

Je pose cette question car dans une question similaire, j'ai eu une réponse que je devrais définir un déclencheur sur le parent. Cependant, je pensais que la simple définition de la clé étrangère m'empêcherait de supprimer le parent si un enfant existe.

18
user1943020

Depuis la page column_constraint sur MSDN :

SUR SUPPRIMER {PAS D'ACTION | CASCADE | SET NULL | DÉFINIR PAR DEFAUT }

Spécifie l'action qui se produit sur les lignes de la table qui est modifiée, si ces lignes ont une relation référentielle et que la ligne référencée est supprimée de la table parent. La valeur par défaut est AUCUNE ACTION .

Ainsi, vous pouvez élider ON DELETE NO ACTION si vous le souhaitez et cela fonctionnera tout de même.

AUCUNE ACTION signifie que rien ne se passera lorsque vous supprimez de votre table Sujet dans la table Sujet. Dans ce cas, s'il existe une ligne dans la rubrique pour un SubjectId donné, vous ne pouvez pas en supprimer sans rompre l'intégrité référentielle, de sorte que la suppression sera annulée.

Plus de MSDN:

AUCUNE ACTION - Le moteur de base de données SQL Server génère une erreur et l'action de suppression sur la ligne de la table parent est annulée.

30
DaveShaw

Je vais vous suggérer que même si vous pouvez ignorer la suppression, aucune action, il n'est peut-être pas dans votre intérêt de le faire. Le fait d'avoir spécifié cela dans la définition de la table peut empêcher plus tard quelqu'un d'ajouter une suppression en cascade car il a vu que vous ne vouliez pas que cela se produise. Cela est particulièrement vrai lorsque vous scriptez correctement tous les objets de base de données et les placez dans le contrôle de code source et que le réviseur de code voit qu'il y a une différence et demande pourquoi cela s'est produit. Trop souvent, les gens sont trop désireux d'ajouter des suppressions en cascade et de détruire des données qui auraient dû être conservées (comme les dossiers financiers d'un client qui n'est plus valide). Ils le font parce qu'ils obtiennent l'erreur qui ne les laisse pas supprimer et veulent juste s'en débarrasser au lieu de se rendre compte que cela les sauve d'une erreur massive. Au moins si vous avez le code pour supprimer aucune action dans votre script de table, les futurs responsables verront que c'était intentionnel et pas seulement que vous avez oublié de configurer des suppressions en cascade. Bien sûr, si votre dba n'autorise pas les suppressions en cascade (comme beaucoup ne le font pas et pour une bonne raison!), Ce n'est pas un problème potentiel, mais spécifier votre intention est souvent une bonne chose pour la maintenabilité.

4
HLGEM

"ON DELETE NO ACTION" est en fait identique à "ON DELETE".

Je suis d'accord qu'il serait bon de l'utiliser pour clarifier que le programmeur a pensé à l'action requise lors de la suppression d'un "en-tête" et a décidé que l '"en-tête" ne devrait pas être supprimé s'il y avait des "lignes" associées. Cependant, je suis en train de définir ma base de données dans Visual Studio et il refuse de mettre à jour le changement de "ON DELETE" à "ON DELETE NO ACTION". Il est toujours "ON DELETE" lorsque je le rafraîchis.

0
TomLak