5

別のエンティティ (b) から参照される自己依存エンティティ (a) がデータベースにあり、特定の (b) エンティティが与えられた場合、必要なすべての (a) エンティティを取得する必要があります。これらは多対多のマッピングであるため、別のマッピング テーブルがあります。CTE を使用した再帰的な Select が最善の策だと思いますが、問題が発生しています。

このフィドルは私の問題を示しています。一部のユーザーが循環参照を導入すると、私の再帰的選択はきしみ音を立てて停止します。私はこれを修正する方法を見つけようと頭を悩ませてきました。フィドルで外部キーを導入しましたが、外部キーは実際には私が使用しているシステムでは受け入れられないことに注意してください (DBA との長年の議論) - データフローをより明確にするためにそれらを導入しました。

フィドルをクリックしたくない人のための再帰クエリ:

WITH recur(objID) AS (
    SELECT usesObjID
        FROM #otherObj
        WHERE otherObjID = 1
    UNION ALL
    SELECT slaveObjID
        FROM #objMap
            INNER JOIN recur
                on #objMap.masterObjID = recur.objID
)SELECT objID from recur

アイデアはありますか?この設計は運用段階ではないため、スキーマを多少変更することはできますが、T-SQL で実行できる場合を除き、挿入時に循環参照を検出することに依存したくありません。

4

1 に答える 1

8

無限ループを防ぐ CTEを設定することは可能MAXRECURSIONですが、最大再帰に達するまでクエリがループ内で実行され続けるため、奇妙な結果が得られます。

課題は、ループに複数のステップが含まれていることです。そのため、ループに入っているかどうかを判断するために、子の直接の親を確認することはできません。

これを処理する 1 つの方法は、CTE に追加の列を追加することです... この新しい列 は tree、これまでに含まれていたすべての ID を追跡し、ID が繰り返されると停止します。

WITH recur(objID, Tree) AS (
    SELECT 
        usesObjID, 
        CAST(',' + CAST(usesObjID AS VARCHAR) + ',' AS VARCHAR) AS Tree
    FROM otherObj
    WHERE otherObjID = 1
    UNION ALL
    SELECT 
        slaveObjID, 
        CAST(recur.Tree + CAST(slaveObjID AS VARCHAR) + ',' AS VARCHAR) AS Tree
    FROM objMap
        INNER JOIN recur
            ON objMap.masterObjID = recur.objID
    WHERE recur.Tree NOT LIKE '%,' + CAST(slaveObjID AS VARCHAR) + ',%'  
)SELECT objID from recur

SQLフィドルリンク

于 2012-12-12T15:52:13.117 に答える