私は共変を強制するためにあらゆる手段を知りませんグループの一意性基準を、標準的な一意性制約またはチェック制約、または他のどのような優雅な解決策によっても解決できます。ただし、ストアド・プロシージャまたは「INSTEAD OF INSERT」トリガーが定義されたビューを介してのみ、表へのアクセスを許可することで、制約を適用することができます。
方法1 - 次の例では、ストアドプロシージャ方法を示す手順
ストアド。最初に、テーブル変数型を作成して、共変量グループを読み取り専用パラメータとしてストアドプロシージャに渡すことができます。
CREATE TABLE CovariateGroupIDs
(
[GroupID] INT PRIMARY KEY IDENTITY
,[CreatedDateTime] DATETIME NOT NULL
)
:私たちは私たちのIDを自動生成するために使用されるダミーのテーブルを作成し
CREATE TABLE CovariateGroups
(
[ID] INT NOT NULL
,[Rank] INT NOT NULL
,[Covariate] NVARCHAR(50)
PRIMARY KEY([ID], [Rank], [Covariate])
)
次のステップ:
CREATE TYPE CovariateGroupEntry AS TABLE
(
[Rank] INT NOT NULL
,[Covariate] NVARCHAR(50)
PRIMARY KEY([Rank], [Covariate])
)
次は、私たちは共変グループが含まれています私たちのベーステーブルを作成します
手順の最終ステップ:
CREATE PROCEDURE CovariateGroup_Add
(
@covariateGroupEntry dbo.CovariateGroupEntry READONLY
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @groupID INT;
DECLARE @groupSize INT;
DECLARE @groupMatchCount INT;
DECLARE @minRank INT;
DECLARE @maxRankDelta INT;
DECLARE @minRankDelta INT;
-- Get the size of the new group which user will attempt to add.
SELECT @groupSize = COUNT([Rank])
FROM @covariateGroupEntry
-- Validate that the new group rank starts at 1 and increments by 1 step value only.
SELECT @minRank = ISNULL(MIN([Rank]), 0)
,@maxRankDelta = ISNULL(MAX(Delta), 0)
,@minRankDelta = ISNULL(MIN(Delta), 0)
FROM (
SELECT [Rank]
,[Rank] - (LAG([Rank], 1, 0) OVER (ORDER BY [Rank])) AS Delta
FROM @covariateGroupEntry
) RankValidation
IF ((@minRank > 1) OR (@maxRankDelta > 1) OR (@minRankDelta < 1))
BEGIN
-- Raise an error if our input data sets rank column does not start at 1 or does not increment by 1 as expected.
RAISERROR (N'Attempting to add covariant group with invalid rank order.', -- Message text.
15, -- Severity,
1 -- State
); -- Second argument.
END
ELSE
BEGIN
-- Generate a new group ID
INSERT INTO [dbo].[CovariateGroupIDs]
(
[CreatedDateTime]
)
SELECT GETDATE() AS [CreatedDateTime]
SET @groupID = SCOPE_IDENTITY();
WITH CTE_GroupsCompareSize
AS
(
-- Compare the size of the new group with all of the existing groups. If the size is different we can
-- safely assume that the group is either a sub set or super set of the compared group. These groups
-- can be excluded from further consideration.
SELECT [CovariateGroups].[ID]
,[CovariateGroups].[Rank]
,[CovariateGroups].[Covariate]
,COUNT([CovariateGroups].[Rank]) OVER (PARTITION BY [CovariateGroups].[ID]) GroupSize
,@groupSize AS NewGroupSize
FROM [CovariateGroups]
)
,CTE_GroupsCompareRank
AS
(
-- For groups of the same size left outer join the new group on the original groups on both rank and covariant entry.
-- If the MIN() OVER window function return a value of 0 then there is at least on entry in the compared groups that does
-- not match and is therefore deemed different.
SELECT [OrginalGroup].[ID]
,[OrginalGroup].[Rank]
,[OrginalGroup].[Covariate]
,MIN(
CASE
WHEN [NewGroup].[Covariate] IS NULL THEN 0
ELSE 1
END
) OVER (PARTITION BY [OrginalGroup].[ID]) AS EntireGroupRankMatch
FROM CTE_GroupsCompareSize [OrginalGroup]
LEFT OUTER JOIN @covariateGroupEntry [NewGroup] ON ([OrginalGroup].[Rank] = [NewGroup].[Rank] AND [OrginalGroup].[Covariate] = [NewGroup].[Covariate])
WHERE GroupSize = NewGroupSize
)
SELECT @groupMatchCount = COUNT(EntireGroupRankMatch)
FROM CTE_GroupsCompareRank
WHERE EntireGroupRankMatch = 1
IF ISNULL(@groupMatchCount, 0) = 0
BEGIN
INSERT INTO [CovariateGroups]
(
[ID]
,[Rank]
,[Covariate]
)
SELECT @groupID AS [ID]
,[Rank]
,[Covariate]
FROM @covariateGroupEntry
END
ELSE
BEGIN
-- Raise an error if our uniqueness constraints are not met.
RAISERROR (N'Uniqueness contain violation, the covariant set is not unique with table "CovariateGroups".', -- Message text.
15, -- Severity,
1 -- State
); -- Second argument.
END
END
END
方法2 - トリガーで表示する
2番目の方法では、ビューを使用して、ビューに挿入トリガーの代わりに作成する方法があります。
まず、我々は次のようにビューを作成します。
CREATE VIEW CovariateGroupsView
AS
SELECT [ID]
,[Rank]
,[Covariate]
FROM CovariateGroups
はその後、我々は、トリガーを作成します。
ALTER TRIGGER CovariateGroupsViewInsteadOfInsert on CovariateGroupsView
INSTEAD OF INSERT
AS
BEGIN
DECLARE @groupID INT;
DECLARE @groupSize INT;
DECLARE @groupMatchCount INT;
DECLARE @minRank INT;
DECLARE @maxRankDelta INT;
DECLARE @minRankDelta INT;
-- Get the size of the new group which user will attempt to add.
SELECT @groupSize = COUNT([Rank])
FROM inserted
-- Validate that the new group rank starts at 1 and increments by 1 step value only.
SELECT @minRank = ISNULL(MIN([Rank]), 0)
,@maxRankDelta = ISNULL(MAX(Delta), 0)
,@minRankDelta = ISNULL(MIN(Delta), 0)
FROM (
SELECT [Rank]
,[Rank] - (LAG([Rank], 1, 0) OVER (ORDER BY [Rank])) AS Delta
FROM inserted
) RankValidation
IF ((@minRank > 1) OR (@maxRankDelta > 1) OR (@minRankDelta < 1))
BEGIN
RAISERROR (N'Attempting to add covariant group with invalid rank order.', -- Message text.
15, -- Severity,
1 -- State
); -- Second argument.
END
ELSE
BEGIN
-- Generate a new group ID
INSERT INTO [dbo].[CovariateGroupIDs]
(
[CreatedDateTime]
)
SELECT GETDATE() AS [CreatedDateTime]
SET @groupID = SCOPE_IDENTITY();
WITH CTE_GroupsCompareSize
AS
(
-- Compare the size of the new group with all of the existing groups. If the size is different we can
-- safely assume that the group is either a sub set or super set of the compared group. These groups
-- can be excluded from further consideration.
SELECT [CovariateGroups].[ID]
,[CovariateGroups].[Rank]
,[CovariateGroups].[Covariate]
,COUNT([CovariateGroups].[Rank]) OVER (PARTITION BY [CovariateGroups].[ID]) GroupSize
,@groupSize AS NewGroupSize
FROM [CovariateGroups]
)
,CTE_GroupsCompareRank
AS
(
-- For groups of the same size left outer join the new group on the original groups on both rank and covariant entry.
-- If the MIN() OVER window function return a value of 0 then there is at least on entry in the compared groups that does
-- not match and is therefore deemed different.
SELECT [OrginalGroup].[ID]
,[OrginalGroup].[Rank]
,[OrginalGroup].[Covariate]
,MIN(
CASE
WHEN [NewGroup].[Covariate] IS NULL THEN 0
ELSE 1
END
) OVER (PARTITION BY [OrginalGroup].[ID]) AS EntireGroupRankMatch
FROM CTE_GroupsCompareSize [OrginalGroup]
LEFT OUTER JOIN inserted [NewGroup] ON ([OrginalGroup].[Rank] = [NewGroup].[Rank] AND [OrginalGroup].[Covariate] = [NewGroup].[Covariate])
WHERE GroupSize = NewGroupSize
)
SELECT @groupMatchCount = COUNT(EntireGroupRankMatch)
FROM CTE_GroupsCompareRank
WHERE EntireGroupRankMatch = 1
IF ISNULL(@groupMatchCount, 0) = 0
BEGIN
INSERT INTO [CovariateGroups]
(
[ID]
,[Rank]
,[Covariate]
)
SELECT @groupID AS [ID]
,[Rank]
,[Covariate]
FROM inserted
END
ELSE
BEGIN
RAISERROR (N'Uniqueness contain violation, the covariant set is not unique with table "CovariateGroups".', -- Message text.
15, -- Severity,
1 -- State
); -- Second argument.
END
END
END;
次の例では、ストアドプロシージャを実行すべきかを示しています。
DECLARE @covariateGroupEntry AS dbo.CovariateGroupEntry
-- INSERT GROUP 1 -------------------
INSERT INTO @covariateGroupEntry
(
[Rank]
,[Covariate]
)
SELECT 1 ,'Age' UNION ALL
SELECT 2 ,'Gender' UNION ALL
SELECT 3 ,'YearOfBirth'
EXEC CovariateGroup_Add @covariateGroupEntry
次の例は、ビューを使用してグループを挿入する方法を示しています。
DECLARE @covariateGroupEntry AS dbo.CovariateGroupEntry
-- INSERT GROUP 1 -------------------
INSERT INTO @covariateGroupEntry
(
[Rank]
,[Covariate]
)
SELECT 1 ,'Age' UNION ALL
SELECT 2 ,'Gender' UNION ALL
SELECT 3 ,'YearOfBirth'
INSERT INTO [dbo].[CovariateGroupsView]
(
[Rank]
,[Covariate]
)
SELECT [Rank]
,[Covariate]
FROM @covariateGroupEntry
DELETE @covariateGroupEntry -- Delete our memory table if we intend to use it again.
一般に、ストアドプロシージャより多くのエッジケースの影響を受けやすく、予期しない動作が発生する可能性があるため、ビューメソッドを使用しないでください。
ビュー上のトリガーは、すべての行を別々のデータセット/グループとして扱うため、期待通りに機能しません。その結果、検証チェックは失敗します。
ランクは連続していて、「1」から始める必要がありますか?そうでなければ、性別の挿入だけが、ランク2で禁止され、あなたのルールによって許可されているようです... –
真。ランクは1から始まり、グループ内の共変量ごとに1ずつ増加します。私はそれを指定するべきだった。 – mortysporty