1

この質問のタイトルを明確にする方法がわかりませんでしたので、これが私の最善の説明です。

私のクライアントには、互いに親子関係にある一連のテーブルがあります。例えば:

CREATE TABLE dbo.First_Level (
    id INT IDENTITY(1, 1) NOT NULL,
    name VARCHAR(20) NOT NULL,
    active BIT NOT NULL DEFAULT(1),
    CONSTRAINT PK_First_Level PRIMARY KEY CLUSTERED (id)
)

CREATE TABLE dbo.Second_Level (
    id INT IDENTITY(1, 1) NOT NULL,
    first_level_id INT NOT NULL,
    name VARCHAR(20) NOT NULL,
    active BIT NOT NULL DEFAULT(1),
    CONSTRAINT PK_Second_Level PRIMARY KEY CLUSTERED (id),
    CONSTRAINT FK_SecondLevel_FirstLevel FOREIGN KEY (first_level_id) REFERENCES dbo.First_Level (id)
)


CREATE TABLE dbo.Third_Level (
    id INT IDENTITY(1, 1) NOT NULL,
    second_level_id INT NOT NULL,
    name VARCHAR(20) NOT NULL,
    active BIT NOT NULL DEFAULT(1),
    CONSTRAINT PK_Third_Level PRIMARY KEY CLUSTERED (id),
    CONSTRAINT FK_ThirdLevel_SecondLevel FOREIGN KEY (second_level_id) REFERENCES dbo.Second_Level (id)
)

注意が必要なのは、親がアクティブではなくなった (アクティブ = 0) とマークされている場合、その下にあるすべての子もアクティブではないと見なす必要があることです。ただし、親がまだアクティブであっても、子は非アクティブとしてマークされる場合があります。

これらのビジネス ルールを適用する最善の方法についての提案を探しています。ビューをオーバーレイして、すべての親を調べて、特定の行の最終的なアクティブ フラグを決定することもできますが、私のクライアントには、これらのテーブルに関する大量のコードが既に記述されています。

トリガーを介してルールを強制することもできますが、これを行うためのよりエレガントな方法があることを願っています。

ありがとう!

4

3 に答える 3

1

個人的にビジネスルールをデータベースに入れるのは好きではありませんが、これに関しては開発が分かれています。とにかく、これは論理レベルから、つまり基になるテーブルを変更せずに、説明したルールを適用するソリューションです。これにより、更新を制限し、すべてのテーブルの各行のアクティブ/非アクティブ状態が他の行と密接に結合されないようにすることができます。

SELECT
    FL.id AS FirstLevelId
    ,FL.active AS FirstLevelActive
    ,SL.id AS SecondLevelId
    -- If First Level is Active, ignore it by passing it as NULL to coalesce, and take the value of Second_Level.active
    -- If First Level is not active, take its value as the "active" value for this level. 
    ,COALESCE(NULLIF(FL.active, 1), SL.active) AS SecondLevelActive
    ,TL.id AS ThirdLevelId
    -- Same as above, but with one more level involved
    ,COALESCE(NULLIF(FL.active, 1), NULLIF(SL.active, 1), TL.active) AS ThirdLevelActive
FROM
    First_Level FL
    LEFT JOIN
    Second_Level SL ON
        (SL.first_level_id = FL.id)
    LEFT JOIN
    Third_Level TL ON
        (TL.second_level_id = SL.id)

利点
- アクティブ ステータスは、ビジネス ルールを適用することによって取得されますが、レベルのデータはそのまま残ります。
- 更新は必要ないため、カスケード更新を追跡したり、トリガーを使用したりする必要はありません。
- このクエリをビューに配置することにより、アプリケーションは常に「その場で」正しいステータスを取得します

欠点
- テーブル構造のため、ソリューションが硬直的です
- 新しい弁護士を追加するには、それに応じてクエリを変更する必要があります

謝辞
刺激的な音楽を提供してくれた、トイレット ストーリー 4 の作曲者である Ghidorah に感謝します。

于 2012-07-18T22:01:55.643 に答える
1

現在アクティブなトップ レベル エントリのセットは、トップレベル エントリのセット トップレベル全体に対する RESTRICT ビューです。

CREATE VIEW FIRST_LEVEL_ACTIVE AS SELECT * FROM FIRST_LEVEL WHERE ACTIVE ... ;

現在アクティブな第 2 レベルのエントリのセットは、エントリ自体がまだアクティブであり、定義したばかりのビューにその親が表示されるという条件を満たすものです。

CREATE VIEW SECOND_LEVEL_ACTIVE AS (SELECT * FROM SECOND_LEVEL WHERE ACTIVE ...) NATURAL JOIN FIRST_LEVEL_ACTIVE; /* または NATURAL JOIN と同じ効果を達成するその他の操作 */

現在アクティブな第 3 レベルのエントリのセットは、エントリ自体がまだアクティブであり、その親が SECOND_LEVEL_ACTIVE に表示されるという条件を満たすエントリです。

などなど

これらのビューに対する UPDATE を処理するために、SQL 標準には INSTEAD OF トリガーがあります。

于 2012-07-19T10:18:59.583 に答える
0

アクティブなステータスを更新するときに update ステートメントで子も更新することで、ビジネス ルールを適用できます。

-- Delete first level
DECLARE @FirstLevelIdToDelete INT
SET @FirstLevelIdToDelete = x

UPDATE  Third_Level
SET     Third_level.active = 0
FROM    Third_Level tl
JOIN    Second_Level sl ON tl.second_level_id = sl.id
WHERE   sl.first_level_id = @FirstLevelIdToDelete

UPDATE  Second_Level
SET     active = 0
WHERE   Second_Level.first_level_id = @FirstLevelIdToDelete

UPDATE  First_Level
SET     active = 0
WHERE   id = @FirstLevelIdToDelete

-- Delete second level
DECLARE @SecondLevelIdToDelete INT
SET @SecondLevelIdToDelete = x

UPDATE  Third_Level
SET     active = 0
WHERE   Third_Level.second_level_id = @SecondLevelIdToDelete

UPDATE  Second_Level
SET     active = 0
WHERE   id = @SecondLevelIdToDelete

-- Delete third level
DECLARE @ThirdLevelIdToDelete INT
SET @ThirdLevelIdToDelete = x

UPDATE  Third_Level
SET     active = 0
WHERE   id = @ThirdLevelIdToDelete
于 2012-07-18T19:34:36.773 に答える