2009-06-13 7 views

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] 
+1

mais une fois trouvé, quel est le meilleur moyen de provoquer un échec d'insertion/mise à jour en utilisant un déclencheur? – MatBailie

+1

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? –

+1

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

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 
Questions connexes