2016-08-26 6 views
1

A列に同じ値の行がすでに存在し、Bの値が異なる場合、挿入/更新を拒否する制約が必要です。TSQLは、同じ列Aを持ち、異なる列Bの値を持つ行は存在しないように制約しますか?

だから:

Insert TableName(A, B) Values(x, y) 
Insert TableName(A, B) Values(x, y) 
Insert TableName(A, B) Values(x, z) 

は、Y =/= zと inserに失敗します。あるいは、テーブルに既に行(x、w)があった場合は、最初の挿入時にも。

一方、これらのインサートが有効です。

Insert TableName(A, B) Values(c, y) 
Insert TableName(A, B) Values(d, y) 

最終発言。データは正規化されません。ノーマライズされていないフォームは、バグではなく機能です。だから私は拘束を求めている。

SQL Server 2008 R2。

あなたは(@Damien_The_Unbelieverのコメントに基づいて修正して)INSTEAD OFトリガーを使用することができます
+0

あなたの制約の背後にあるロジックを実際には得られません。なぜ最初の部分が失敗し、2番目の部分が合格するはずですか? – Rahul

答えて

1

あなたはindexed viewでこれを達成することができます:

create table dbo.T (
    A char(1) not null, 
    B char(1) not null 
) 
go 
create view dbo.V_T 
with schemabinding 
as 
    select 
     A, 
     B, 
     COUNT_BIG(*) as Cnt 
    from 
     dbo.T 
    group by 
     A,B 
go 
create unique clustered index IX_V_T on dbo.V_T (A) 
go 
Insert T(A, B) Values('x', 'y') 
Insert T(A, B) Values('x', 'y') 
Insert T(A, B) Values('x', 'z') 

第三のインサートは、エラーが発生します。

Msg 2601, Level 14, State 1, Line 1 
Cannot insert duplicate key row in object 'dbo.V_T' with unique index 'IX_V_T'. The duplicate key value is (x). 
The statement has been terminated. 

そして継続:

Insert T(A, B) Values('c', 'y') 
Insert T(A, B) Values('d', 'y') 

両方とも正常に実行されます。


V_Tテーブルのデザインは、それが各一意A,B組合せに対して1つの行を有するようなものである(COUNT_BIG(*)これは、インデックス付きビューをすることを可能にするだけ必要であり、我々は、DISTINCTの使用を許可していません) 。次に、Aの値にユニークなインデックスを設定するだけです。したがって、このビューには、可能な各A値に対して1つの行しか含めることができないか、またはユニーク制約が違反されます。

+0

どのように動作するのかについての説明はありますか? –

+0

@przemo_li - 一番下に説明が追加されました。 –

2

最初にテーブルを作成します。

CREATE TABLE temp (
    A nchar(1), 
    B nchar(1) 
); 

トリガーを作成します。次に

CREATE TRIGGER testtemp 
ON temp 
INSTEAD OF INSERT, UPDATE 
AS 
INSERT INTO temp 
SELECT A, 
     B 
FROM (
    SELECT i.*, 
      DENSE_RANK() OVER (PARTITION BY i.A ORDER BY i.A,i.B) as DR 
    FROM inserted i 
    OUTER APPLY (
      SELECT TOP 1 * 
      FROM temp 
      WHERE A = i.A 
     ) t 
    WHERE t.b IS NULL OR t.B = i.B 
    ) C 
where dr = 1 

DELETE t 
FROM temp t 
INNER JOIN deleted d 
    ON d.A=t.A and d.B=t.B; 

実行を:

Insert temp(A, B) Values 
('x','y'), 
('x','y'), 
('x','z'), 
('c','y'), 
('d','y'), 
('a','b'), 
('a','c'); 

出力:

A B 
a b 
c y 
d y 
x y 
x y 
+0

私の質問を「y =/= zとして2番目の挿入に失敗する」と答えていますが、「xは一意ではない」ためあなたの答えは失敗します。それは大きな違いです;) –

+0

X、yが挿入されます。x、zは挿入されません。それはあなたが要求した論理ですか?私は一意のCONSTRAINTを追加します。 – gofr1

+0

私の質問は十分ではなかった。 I(x、y)(x、y)(x、z)は3回目の挿入時にのみ失敗します。 –

関連する問題