TSQL约束,以便不能有具有相同列A但不同列B值的行?

时间:2016-08-26 09:20:42

标签: sql-server sql-server-2008-r2 constraints

如果A列中的某些行具有相同的值但B中的值不同,则需要限制拒绝插入/更新。

所以:

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

第三 inser将失败,因为y = / = z。或者甚至在第一次插入时,如果表中已经有行(x,w)。

另一方面,这些插入有效:

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

最后一句话。数据不会被标准化。非规范化表单是一个功能而不是错误。这就是我要求约束的原因。

SQL Server 2008R2。

2 个答案:

答案 0 :(得分:2)

您可以使用INSTEAD OF触发器(根据@Damien_The_Unbeliever的评论进行修复):

首先创建一个表:

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

答案 1 :(得分: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组合都有一行(COUNT_BIG(*)只是允许它成为索引视图的一个要求,我们'不允许使用DISTINCT)。然后,我们只在A值上添加一个唯一索引。因此,此视图对于每个可能的A值只能包含一行,否则将违反唯一约束。