【问题标题】:SQL uniqueness constraint when using wildcard values使用通配符值时的 SQL 唯一性约束
【发布时间】:2013-09-02 20:24:14
【问题描述】:

请考虑下表,该表指定了一周中给定日期禁止食用的水果。 DayOfWeek 可以为空,其中 NULL 表示一周中的所有天都禁止这种类型的水果。

Fruit        DayOfWeek
----------------------
Kiwi         NULL
Apples       Monday
Strawberries Monday
Oranges      Tuesday
Bananas      Wednesday
Pineapple    Thursday

是否可以在此表上实施约束以阻止我插入值 (Kiwi, Monday),因为现有的 (Kiwi, NULL) 行已经在星期一(和每隔一天)禁止新西兰人。

最好在不使用触发器的情况下实现这一点

【问题讨论】:

  • 这不是唯一性约束,它只是一个业务规则。

标签: sql-server constraints


【解决方案1】:

除非你有一个非常好的理由,否则你不应该改变 NULL 的含义。 Null 反映了一个未知的值,所以我会读这个,因为我们不知道一周中的哪一天猕猴桃被禁止。然后,您将更改逻辑以存储一周中禁止 Kiwi 的每一天的记录。

如果你需要写一个查询,上面写着给我所有的星期一禁果怎么办?您需要将查询编写为

select * from BadFruit where DayOfWeek='Monday' || DayOfWeek is null

更有效且更易于理解的查询将消除 or 子句。

【讨论】:

    【解决方案2】:

    我同意其他人的观点,即我可能会瞄准与您展示的型号不同的型号,但如果您对它出售,那么以下似乎可以满足您的需求:

    create table dbo.Weekdays (
        DayOfWeek varchar(10) not null,
        constraint PK_Weekdays PRIMARY KEY (DayOfWeek)
    )
    go
    create table dbo.Exclusions (
        Fruit varchar(20) not null,
        DayOfWeek varchar(10) null,
        /* PK? */
        constraint FK_Exclusions FOREIGN KEY (DayOfWeek) references Weekdays (DayOfWeek)
    )
    

    不确定排除表的 PK 应该是什么,从您显示的内容来看并不明显,但它旨在成为您的表。我们需要引入Weekdays 表才能使后面的视图工作*。现在填充它:

    insert into dbo.Weekdays (DayOfWeek)
    select 'Monday' union all
    select 'Tuesday' union all
    select 'Wednesday' union all
    select 'Thursday' union all
    select 'Friday' union all
    select 'Saturday' union all
    select 'Sunday'
    

    还有你的样本数据:

    insert into dbo.Exclusions (Fruit,DayOfWeek)
    select 'Kiwi',NULL union all
    select 'Apples','Monday' union all
    select 'Strawberries','Monday' union all
    select 'Oranges','Tuesday' union all
    select 'Bananas','Wednesday' union all
    select 'Pineapple','Thursday'
    

    现在我们创建视图来实现您的约束:

    create view dbo.Exclusions_NullExpanded
    with schemabinding
    as
        select
            e.Fruit,
            wd.DayOfWeek
        from
            dbo.Exclusions e
                inner join
            dbo.Weekdays wd
                on
                    e.DayOfWeek = wd.DayOfWeek or
                    e.DayOfWeek is null
    go
    create unique clustered index IX_Exclusions_NoDups on dbo.Exclusions_NullExpanded (Fruit,DayOfWeek)
    

    而且,如果我们尝试插入您不希望我们插入的行:

    insert into dbo.Exclusions (Fruit,DayOfWeek)
    select 'Kiwi','Monday'
    

    我们得到:

    Msg 2601, Level 14, State 1, Line 1
    Cannot insert duplicate key row in object 'dbo.Exclusions_NullExpanded' with unique index 'IX_Exclusions_NoDups'.
    The statement has been terminated.
    

    *我最初尝试在不引入 Weekdays 表的情况下执行此操作,并将其作为文本行的子选择出现在视图定义中。但是你不能创建索引来强制我们想要在这样一个视图上的约束。

    【讨论】:

      【解决方案3】:

      我个人不喜欢 NULL 意味着所有的想法,但是当 NULL 可能超出范围时,将其更改为每天包含一行。

      如果触发器不是一个选项,我会查看 CHECK CONSTRAINT 并设置一个函数来测试您试图避免的条件。

      【讨论】:

      • 检查约束可以验证所有行的条件吗?我的印象是 CHECK CONSTRAINT 只能根据单个行中的数据列评估其逻辑。
      • 如果您从约束中调用的函数评估表,您可以这样做。我的偏好仍然是输入触发器,因为它不会使水域变得混乱,所以我可能应该直接说明并让它成为现实。
      【解决方案4】:

      试试这个链接http://www.java2s.com/Code/SQL/Select-Clause/SettingaUniqueConstraint.htm

      对于 MySQL,您可以设置唯一的约束。

      【讨论】:

      • Unique 在这里不起作用,因为 KIWI、NULL 和 KIWI, Monday (invalid per OP) 都可以使用 UNIQUE。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-17
      • 1970-01-01
      • 1970-01-01
      • 2021-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多