sql >> データベース >  >> RDS >> Sqlserver

SQLでの循環参照の検出

    循環参照をチェックするために、トリガーと再帰CTEを使用しました:

    CREATE TRIGGER trgIU_X_CheckCircularReferences
    ON dbo.X
    AFTER INSERT, UPDATE 
    AS
    BEGIN   
        SET NOCOUNT ON;
        DECLARE @Results TABLE ([Exists] BIT);
    
        WITH CteHierarchy
        AS
        (
            SELECT  x.A, x.B, X.C, 1 AS [Type]
            FROM    inserted i
            JOIN    X x ON i.A = x.A AND i.C = x.B
            UNION ALL
            SELECT  x.A, x.B, X.C, 2 AS [Type]
            FROM    CteHierarchy i
            JOIN    X x ON i.A = x.A AND i.C = x.B
            WHERE   NOT EXISTS 
            (
                    SELECT  *
                    FROM    inserted a
                    WHERE   a.A = x.A AND a.B = x.B
            )   
        )
        INSERT  @Results ([Exists])
        SELECT  TOP(1) 1
        FROM    CteHierarchy h
        JOIN    X x ON h.A = x.A AND h.C = x.B
        OPTION(MAXRECURSION 1000);
    
        IF EXISTS(SELECT * FROM @Results)
        BEGIN
            ROLLBACK;
            RAISERROR('Circular references detected', 16, 1);
        END
    END
    GO
    

    これで、いくつかのテストを実行できます:

    --Test 1 - OK
    PRINT '*****Test 1 - OK*****';
    SELECT * FROM X;
    
    BEGIN TRANSACTION;
    
    UPDATE  X 
    SET     C = 'B1'
    WHERE   B = 'B4';
    
    SELECT * FROM X;
    
    --This transaction can be commited without problems
    --but I will cancel all modification so we can run the second test
    ROLLBACK TRANSACTION;
    PRINT '*****End of test 1*****';    
    GO
    
    --Test 2 - NOT OK
    PRINT '*****Test 2 - NOT OK*****';
    SELECT * FROM X;
    
    BEGIN TRANSACTION;
    
    UPDATE  X 
    SET     C = 'B1'
    WHERE   B = 'B1';
    
    --Useless in this case (test 2 & test 3)
    --Read section [If a ROLLBACK TRANSACTION is issued in a trigger] from http://msdn.microsoft.com/en-us/library/ms181299.aspx
    SELECT * FROM X;
    --Useless
    ROLLBACK TRANSACTION;
    --Useless
    PRINT '*****End of test 2*****';        
    GO
    
    PRINT '*****Test 3 - NOT OK*****';
    SELECT * FROM X;
    
    BEGIN TRANSACTION;
    
    UPDATE  X 
    SET     C = 'B4'
    WHERE   B = 'B1';
    GO
    

    結果:

    *****Test 1 - OK*****
    
    (4 row(s) affected)
    
    (0 row(s) affected)
    
    (1 row(s) affected)
    
    (4 row(s) affected)
    *****End of test 1*****
    *****Test 2 - NOT OK*****
    
    (4 row(s) affected)
    
    (1 row(s) affected)
    Msg 50000, Level 16, State 1, Procedure trgIU_X_CheckCircularReferences, Line 34
    Circular references detected
    Msg 3609, Level 16, State 1, Line 8
    The transaction ended in the trigger. The batch has been aborted.
    *****Test 3 - NOT OK*****
    
    (4 row(s) affected)
    
    (1 row(s) affected)
    Msg 50000, Level 16, State 1, Procedure trgIU_X_CheckCircularReferences, Line 34
    Circular references detected
    Msg 3609, Level 16, State 1, Line 7
    The transaction ended in the trigger. The batch has been aborted.
    

    2番目のテストでは、このトリガーがどのようにキャンセルされたかを確認できます(ROLLBACK TRANSACTION )トランザクションと、UPDATE後、何も実行されていません(現在のバッチ




    1. phpを介してmysqlに大きなテキストを保存できません

    2. この配列構造をHTMLフォームで作成するにはどうすればよいですか?

    3. MySQLの更新に(あまりにも)長い時間がかかる

    4. MySqlは、制限を使用せずに次に小さい番号を選択します