【问题标题】:Define a unique constraint between combinations in 2 columns and a third column在 2 列和第三列的组合之间定义唯一约束
【发布时间】:2019-02-14 23:55:21
【问题描述】:

在下表中,(colA, colB, colC) 是主键。在colD中,我定义了一种新的id类型,每个(colA,colB)组合都是唯一的,即:

colD = f(colA,colB)

所以 (A,1) 应该给我 id_1,(B,2) 对应于 id_2 等,其中 id 是整数值。下表显示了一个错误,其中 (A,1) 有 2 个 id - id_1 和 id_2。

我想强制执行一个约束,即每对值 (colA,colB) 映射到 colD 中的一个且只有一个值。当然,我可以为 (colA,colB,colC,colD) 添加唯一约束,因为 (colA,colB,colC) 是主键,但这不会检测 colC 和 colD 同时发生变化。

我不确定这里最好的方法是什么。

 +colA + colB + colC + colD +
 +--------------------------+
 | A   |  1   |180901| id_1 |
 | A   |  1   |180902| id_1 |
 | A   |  1   |180903| id_1 |
 | A   |  1   |180904| id_2 |
 | .   |  .   |  .   |  .   |
 | .   |  .   |  .   |  .   |
 | .   |  .   |  .   |  .   |
 |     |      |      |      |
 |     |      |      |      |
 |     |      |      |      |
 |     |      |      |      |

【问题讨论】:

  • 创建一个视图而不是存储计算值。 (或者有一个计算列。)
  • @jarlh 的重点是最终,primkey 将是 (colD,colC) 而 colA, colB 将被删除。
  • 为什么不能为 (cola, colb, cold) 创建一个唯一的索引/约束?
  • @SalmanA - 因为在他们的样本中,他们有 3 行的组合 (A,1,id_1) 并且他们希望允许这样做

标签: sql sql-server tsql


【解决方案1】:

您可以使用索引视图强制执行此约束:

create table dbo.T (colA char(1) not null, colB int not null,
colC int not null, colD varchar(6) not null,
constraint PK_T PRIMARY KEY (colA,colB,colC))
go
create view dbo.DRI_T
with schemabinding
as
    select colA,colB,colD,COUNT_BIG(*) as Cnt
    from dbo.T
    group by colA,colB,colD
go
create unique clustered index IX_DRI_T on dbo.DRI_T (colA,colB)
go
insert into T(colA,colB,colC,colD)
values ('A',1,180901,'id_1')
go
insert into T(colA,colB,colC,colD)
values ('A',1,180902,'id_1')
go
insert into T(colA,colB,colC,colD)
values ('A',1,180903,'id_1')
go
insert into T(colA,colB,colC,colD)
values ('A',1,180904,'id_2')
go

这第四条插入语句产生的错误是:

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

希望您能看到它是如何解决这个错误的。当然,它与直接违反约束的报告并不完全相同,但我认为它包含足够的信息,我很乐意在我的一个数据库中使用它。

如果您想让错误更加明显,您当然可以为DRI_TIX_DRI_T 选择更好的名称。例如。 IX_DRI_T_colD_mismatch_colA_colB

【讨论】:

  • 你也可以用一个函数和一个检查约束来做到这一点,比如alter table t add constraint ck_fn_checkd check (dbo.fn_checkd(a,b) = 1)。但请注意,在功能上依赖于键的子集的非键属性违反了第三范式。您通常会引入由 (a,b) 定义的不同表键来存储依赖于该组合的任何属性。
  • @DavidBrowne-Microsoft - 正如 OP 所指出的,这似乎是某种形式的多步骤转换过程(例如,colD 将在以后替换 colAcolB),所以如果是这种情况,我不太担心规范化。
猜你喜欢
  • 2012-04-26
  • 1970-01-01
  • 2012-05-17
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
  • 2013-03-25
  • 2017-04-23
相关资源
最近更新 更多