2017-08-08 1 views
0

Disons que j'ai une relation directe maître-détail entre deux tables (OrderHeaders et OrderDetails par exemple). Si je souhaite que les enregistrements de détail soient supprimés en même temps que la suppression d'une fiche, je peux définir l'action de suppression sur la relation entre les deux en cascade.SQL Server: comment empêcher qu'un enregistrement soit supprimé si l'une de ses colonnes est égale à une certaine valeur

C'est très bien, les tables sont essentiellement indépendantes de toute autre chose dans la base de données. Cependant, si nous devions transformer une commande en facture à un moment donné, il est clair que l'on ne voudrait pas supprimer une commande ou ses détails connexes.

Dans mon équivalent du tableau OrderHeaders j'ai ajouté une simple colonne booléenne (Posted) qui est définie sur true si une commande a été convertie en une facture.

Quelle est la manière correcte en SQL d'imposer une règle sur la table OrderHeaders pour empêcher la suppression d'un enregistrement si la valeur Posted est égale à true?

S'il y a en fait de meilleures approches à cette situation particulière alors je suis parfaitement ouvert aux suggestions, il est toujours bon d'apprendre quelque chose de nouveau.

Un grand merci

Dom

+0

Si je comprends bien, vous voulez supprimer à partir de Détails quand il y a suppression dans les OrderHeaders, mais cela devrait être conditionnel basé sur l'indicateur Posté qui est dans une autre table? – Sujith

+0

Y a-t-il d'autres éléments stockés lors de la conversion d'une commande en facture? Si oui, cela pourrait-il ne pas avoir un FK à OrderHeaders au lieu de la colonne Posté, et avoir ce FK non cascade? –

+0

@Sujith Le champ Posté se trouve dans la table OrderHeaders elle-même. –

Répondre

0

Il n'y a pas CASCADE conditionnelle. Pour gérer la suppression conditionnelle, définissez un déclencheur pour supprimer manuellement les lignes enfant. (Voir le SQL Server using triggers and geting rid of ON DELETE CASCADE)

+0

J'avais plutôt peur que cela puisse être le cas. Personnellement, je n'aime pas supprimer cascade car il est trop facile de faire quelque chose que vous regrettez plus tard. Dans ce cas, ma meilleure approche pourrait être de filtrer les enregistrements dans l'interface utilisateur en fonction de la valeur affichée et d'activer ou de désactiver le bouton de suppression en conséquence. –

0

Comment créez-vous une facture? Je peux vous dire que SAP, par exemple, copie simplement l'en-tête de la commande et tous ses détails dans les détails de la facture et de la facture, afin que vous puissiez faire ce que vous voulez, mais la facture reste la même. Personnellement, je ne pense pas que ce soit une bonne solution, puisqu'elle conserve deux fois les mêmes données (en fait, si je me souviens bien, c'est toujours pire dans sève - les données sont dupliquées 2, 3, 4 et peut-être même 5 fois) .

Une solution assez simple serait d'ajouter connecter la facture à la table des détails de la commande avec une clé étrangère qui n'est pas en cascade des suppressions. Ainsi, lorsque vous créez la facture, vous la liez aux détails de la commande. Une fois qu'un enregistrement ne peut pas être supprimé du tableau des détails de la commande, son enregistrement parent ne peut pas être supprimé de la table des commandes.

J'ai fait une démonstration simple sur rextester pour vous montrer ce que je veux dire - est ici l'exemple complet (en cas rextester est indisponible):

CREATE TABLE OrderHeader 
(
    id int identity(1,1) primary key, 
    createDate datetime 
); 

CREATE TABLE Invoice 
(
    id int identity(1,1) primary key, 
    createDate datetime, 
    OrderId int foreign key references OrderHeader(id) 
); 

CREATE TABLE OrderDetails 
(
    id int identity(1,1) primary key, 
    orderId int foreign key references OrderHeader(id) on delete cascade, 
    itemId int, 
    invoiceId int NULL foreign key references Invoice(id) 
); 


INSERT INTO OrderHeader (createDate) VALUES (DATEADD(DAY, -1, GETDATE())), (GETDATE()); 

INSERT INTO OrderDetails (orderId, itemId) VALUES (1, 1), (2, 2); 

BEGIN TRANSACTION 

INSERT INTO Invoice (createDate, OrderId) VALUES (GETDATE(), 1) ; 

UPDATE OrderDetails 
SET invoiceId = scope_identity() 
WHERE OrderId = 1; 

COMMIT TRANSACTION 

SELECT 'Headers', * FROM OrderHeader; 
SELECT 'Details', * FROM OrderDetails; 
SELECT 'Invoice', * FROM Invoice; 

DELETE FROM OrderHeader WHERE Id = 2; 

SELECT 'Headers', * FROM OrderHeader; 
SELECT 'Details', * FROM OrderDetails; 
SELECT 'Invoice', * FROM Invoice; 

DELETE FROM OrderHeader WHERE Id = 1;