このタイプの列はネイティブでサポートされていませんが、トリガーを使用して実装できます:
CREATE TRIGGER tr_MyTable_Number
ON MyTable
INSTEAD OF INSERT
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN;
WITH MaxNumbers_CTE AS
(
SELECT ParentEntityID, MAX(Number) AS Number
FROM MyTable
WHERE ParentEntityID IN (SELECT ParentEntityID FROM inserted)
)
INSERT MyTable (ParentEntityID, Number)
SELECT
i.ParentEntityID,
ROW_NUMBER() OVER
(
PARTITION BY i.ParentEntityID
ORDER BY (SELECT 1)
) + ISNULL(m.Number, 0) AS Number
FROM inserted i
LEFT JOIN MaxNumbers_CTE m
ON m.ParentEntityID = i.ParentEntityID
COMMIT
テストしていませんが、うまくいくと確信しています。主キーがある場合は、これを AFTER
として実装することもできます トリガー (INSTEAD OF
の使用は嫌いです) トリガー、6 か月後に変更する必要があるときに理解するのが難しくなります)。
ここで何が起こっているかを説明すると:
- <リ>
SERIALIZABLE
最も厳格な分離モードです。一度に 1 つのデータベース トランザクションのみがこれらのステートメントを実行できることが保証されます。これは、この「シーケンス」の整合性を保証するために必要です。これはトランザクション全体を不可逆的に昇格させるため、長時間実行されるトランザクション内でこれを使用したくないことに注意してください。
CTE は、各親 ID で既に使用されている最大数を取得します。
<リ>
ROW_NUMBER
親 ID ごとに一意のシーケンスを生成します (PARTITION BY
) 番号 1 から開始します。新しいシーケンスを取得する前の最大値がある場合は、これを以前の最大値に追加します。
また、一度に 1 つの新しい子エンティティを挿入するだけでよい場合は、トリガーを使用する代わりに、ストアド プロシージャを介してこれらの操作を処理する方がよいことにも言及する必要があります。これにより、パフォーマンスが確実に向上します。 . hierarchyid
で現在行われている方法は次のとおりです。 SQL '08 の列。