J'ai une table de nœuds avec (NodeId, NodeName) et une table de structure (ParentNodeId, ChildNodeId). Comment puis-je écrire un déclencheur qui vérifie si une instruction de mise à jour ou de suppression d'insert peut provoquer une relation infinie?Déclenchement pour empêcher une boucle infinie dans un arbre SQL
3
A
Répondre
1
Vous devrez vérifier récursivement la condition de dépendance circulaire dans laquelle le parent ne devient pas un enfant de son propre enfant, directement ou indirectement.
Dans SQL Server 2005, vous pouvez écrire un CTE récursif pour le même. Un exemple -
WITH [RecursiveCTE]([Id], [ParentAccountId]) AS
(
SELECT
[Id],
[ParentAccountId]
FROM [Structure]
WHERE [Id] = @Id
UNION ALL
SELECT
S.[Id],
S.[ParentAccountId]
FROM [Structure] S INNER JOIN [RecursiveCTE] RCTE ON S.[ParentAccountId] = RCTE.[Id]
)
SELECT * FROM [RecursiveCTE]
3
Voici ma solution, et jusqu'à présent cela fonctionne comme prévu.
CREATE TRIGGER [dbo].[CheckNodeDependence] ON [dbo].[ObjectTrees]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
DECLARE @CTable TABLE(ChildId INT NOT NULL,
ParentId INT NOT NULL,
[Level] INT NOT NULL,
RowId INT NOT NULL)
DECLARE @Level INT
SET @Level = 1
DECLARE @rows_affected INT
SET @rows_affected = 1
INSERT INTO @CTable
SELECT ObjectId, ParentId, 1, ObjectId FROM INSERTED
WHILE @rows_affected > 0
BEGIN
SET @Level = @Level + 1
INSERT INTO @CTable
SELECT T.ObjectId, T.ParentId, @Level, C.RowId
FROM ObjectTrees T
INNER JOIN @CTable C ON T.ParentId = C.ChildId
AND C.Level = @Level - 1
SET @rows_affected = @@rowcount
IF EXISTS(
SELECT * FROM @CTable B
INNER JOIN @CTable V ON B.level = 1
AND V.Level > 1
AND V.RowId = B.RowId
AND V.ChildId = B.RowId)
BEGIN
DECLARE @error_message VARCHAR(200)
SET @error_message = 'Operation would cause illegal circular reference in tree structure, level = ' + CAST(@Level AS VARCHAR(30))
RAISERROR(@error_message,16,1)
ROLLBACK TRANSACTION
RETURN
END
END
END
GO
mais une fois trouvé, quel est le meilleur moyen de provoquer un échec d'insertion/mise à jour en utilisant un déclencheur? – MatBailie
Selon la plate-forme. Dans Oracle, vous lanceriez une exception, avec autant d'informations utiles que possible dans le texte. Mais vraiment, cela dépend de l'application, n'est-ce pas? –
Oui. Cela dépend de l'application que vous utilisez. Dans SQL Server, vous lancerez également une exception pour arrêter l'insertion. Ou vous pouvez utiliser les déclencheurs Au lieu de et ne rien faire. – Kirtan