【问题标题】:TSQL constrain so that there can not be to rows with same column A but different column B values?T SQL 约束,以便不能存在具有相同 A 列但不同列 B 值的行?
【发布时间】:2016-08-26 09:20:41
【问题描述】:

如果在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。如果表中已经有行 (x, w),甚至在第一次插入时。

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

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

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

SQL Server 2008R2。

【问题讨论】:

  • 真的没有得到约束背后的逻辑。为什么第一部分应该失败而第二部分应该通过?

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


【解决方案1】:

您可以使用 INSTEAD OF 触发器(基于 @Damien_The_Unbeliever 的 cmets 进行修复):

首先创建一个表:

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

【讨论】:

  • 引用我的问题“将在第二个插入器上失败,因为 y =/=z。”,而您的答案将失败,因为“x 不是唯一的”。这是一个很大的不同;)
  • X, y 将被插入 x,z 则不会。这是你要求的逻辑吗?我添加了唯一的约束。
  • 好的。我的问题不够清楚。 I (x,y)(x,y)(x,z) 应该只在第 3 次插入时失败。
  • 我添加触发解决方案
  • 我认为如果遇到违反约束的多行插入,您的触发器可能难以正确操作。
【解决方案2】:

您可以通过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 值,此视图只能包含一行,否则将违反唯一约束。

【讨论】:

  • @przemo_li - 在底部添加了一些解释。
猜你喜欢
  • 1970-01-01
  • 2021-05-26
  • 2021-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多