【问题标题】:SQL Conditional CONSTRAINT FILTERSQL 条件约束过滤器
【发布时间】:2018-09-15 00:29:21
【问题描述】:

我不希望根据以下条件在表中允许重复

例如: 我有

ID  Number  AdditionalID
1   458     1234 <-- 458 must be  allow
2   458     1234 <-- 458 must be allow
3   458     123456 <-- 458 must not be allowed because additionalID is different

4, 459 ,123456

【问题讨论】:

  • 为什么 id 1 和 id 2 允许使用 458 而 id 3 却不允许使用 458?
  • 您使用的是哪个DBMS? “SQL”只是一种查询语言,而不是特定数据库产品的名称。请为您正在使用的数据库产品添加标签postgresqloraclesql-serverdb2、...
  • SQL EXPRESS 2014
  • @jarlh ID 是简单的主键:这将始终以 1 递增(我不在乎)458 可以存在多次,而附加 ID 相同,如果传入的数字是 458然后必须删除 AdditionalID IS Different
  • 如果 458 必须始终与 1234 匹配,为什么不将其作为 single 事实存储在其他表的 single 行中,然后从该表中删除的那些列之一?可以实现此约束,但如果您对数据进行规范化,则不需要。

标签: sql sql-server constraints filtering sql-server-express


【解决方案1】:

解决此问题的最佳方法是规范化您的数据。目前,您正在存储相同、单一事实多次 次。所以我会将NumberAdditionalID 之间的这种关系移动到一个单独的表中1 并从当前表中删除AdditionalID

但如果您坚持不改变结构,我们可以通过indexed view 来实现:

create table dbo.T (
    ID int IDENTITY(1,1) not null,
    Number int not null,
    AdditionalID int not null
)
go
create view dbo.DRI_T
with schemabinding
as
    select
        Number,
        AdditionalID,
        COUNT_BIG(*) as Cnt
    from
        dbo.T
    group by Number,AdditionalID
go
create unique clustered index IX_DRI_T_UniqueAdditionalIDPerNumber on dbo.DRI_T (Number)
go
insert into T(Number,AdditionalID) values
(458,1234),
(458,1234)
go
insert into T(Number,AdditionalID) values
(458,123456) --<-- This insert fails
go
insert into T(Number,AdditionalID) values
(459 ,123456)

这是如何工作的?我们创建一个视图,每个 NumberAdditionalID 列的唯一组合将包含一行。但随后我们声明此视图的键只是Number 列。实际上,这意味着我们实际上只允许为每个 Number 值存储一个这样的组合。


1在那个单独的表中,Number 将是主键,因此当然只有一个AdditionalID 可以与每个Number 关联。实际上,它与此处显示的索引视图非常相似,只是它不需要 Cnt 列,此处仅需要该列,因为它是允许在索引视图中使用 GROUP BY 的要求。

【讨论】:

  • 我无法更改表的结构,但索引视图是非常好的解决方案!谢谢!!
【解决方案2】:

不知道“附加 id”如何允许数字的完整解决方案可能有几个解决方案。

1.外键

如果可能,在这里使用外键可能是最好的解决方案。

ALTER TABLE YourTable
ADD FOREIGN KEY (AdditionalID) REFERENCES AllowedAdditionalId(AdditionalID);

2。使用函数进行约束检查

create function dbo.CheckFunction()
returns int
as begin
    return (select 1)
end

alter table YourTable
add constraint chk_CheckFunction
check (dbo.CheckFunction() = 1)

【讨论】:

  • 我想我理解你的第二个例子的解决方案。我认为这是一种没有功能的方法..让我试试..
  • 仅供参考,我使用选项 2,在函数内部我进行快速搜索并返回一个整数,表示是否会失败或接受它。
  • 采用函数方法意味着您每次都需要(可能)扫描整个表。并且经常遇到无法预测复杂的插入/更新/删除活动的函数。与将多行行为“欺骗”为检查约束的方法相比,我更喜欢声明性方法。
  • @damien_the_unbeliever。但是视图如何不影响性能呢?每次有新行进来的视图怎么触发呢?这会以某种方式自动触发吗?并检查该行进入时的约束?
  • @user2160275 - 在后台维护一个索引视图,其机制与触发器非常相似。除非您不必自己编写它们。正是由于这种类似触发器的机制,对您在索引视图中可以执行的操作的许多限制都存在,并且反过来可以最大限度地减少系统施加的性能损失。 IE。它们仅针对受任何特定 DML 语句影响的行,而不是整个表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-13
  • 2012-05-03
  • 2021-07-22
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 2023-03-27
相关资源
最近更新 更多