【问题标题】:Combining the UNIQUE and CHECK constraints结合 UNIQUE 和 CHECK 约束
【发布时间】:2010-04-07 23:28:31
【问题描述】:

我有一个包含 a b 和 c 列的表,如果 c 为 false,那么我只想在 a 和 b 列唯一的情况下允许插入,但如果 c 为 true,则 a 和 b 不需要唯一。

示例: 表中只能有一个 (foo, bar, false),但可以有多少个 (foo, bar, true)。

我尝试了类似 CONSTRAINT blah UNIQUE (a,b) AND CHECK (C is TRUE) 但我无法找出正确的语法。

【问题讨论】:

  • 哪个数据库? mysql、oracle、postgres、ms sql 等...

标签: sql constraints


【解决方案1】:
  1. 使用过滤器 WHERE C = false 创建返回 a 和 b 的索引视图,然后在视图上创建唯一索引。这是一种通用方法

  2. 如果您有 SQL Server 2008,则改为 create a unique filtered index

  3. 存储过程

  4. 触发器(之前或之后)

【讨论】:

  • 不知道过滤索引
【解决方案2】:

唯一约束适用于所有行,无法仅指定某些行。

检查约束仅用于单行内的验证。

实现您的要求的唯一方法是执行以下任一操作:

1) 创建一个存储过程,其中所有的 INSERT 都是从其中进行的。您可以在此处验证所有逻辑。但是,流氓程序/用户可以避免使用它并破坏您的逻辑。

2) 创建一个触发器来验证您的逻辑并导致无效插入/更新失败。应该写成一次处理一组行

3) 创建一个检查约束,该约束调用一个用户定义的函数来进行验证检查。这被认为是一种不好的做法,应该避免,因为它们非常慢并且可能会因多行更新而失败。

我推荐选项 #2,触发器,因为这正是触发器的设计目的。

【讨论】:

    【解决方案3】:

    您始终可以创建一个触发器,在插入之前检查所需条件。

    【讨论】:

      【解决方案4】:

      您可以使用表约束(取决于 SQL 引擎——不清楚您使用的是哪一个)来确保没有太多特定类型的元组。

      在火鸟 2.1 下:

      fb> CREATE TABLE so2587151 (
        >   a VARCHAR(16) NOT NULL,
        >   b VARCHAR(16) NOT NULL,
        >   c VARCHAR(1) NOT NULL CHECK (c in ('T', 'F')),
        >   CONSTRAINT so2587151_only_one_false CHECK (    -- begin CONSTRAINT
        >     NOT EXISTS (   SELECT a, b, COUNT('x')
        >                      FROM so2587151
        >                     WHERE c = 'F'
        >                  GROUP BY 1, 2
        >                    HAVING COUNT('x') >= 1  )
        >   )                                              -- end CONSTRAINT
        > );
      fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'T');
      fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'T');
      fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'F');
      fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'F');
      Error: Operation violates CHECK constraint  on view or table
      -Operation violates CHECK constraint SO2587151_ONLY_ONE_FALSE on view or table SO2587151
      -At trigger 'CHECK_15'
      fb> SELECT * FROM so2587151;
       A  |  B  | C
      ==============
      foo | bar | T
      foo | bar | T
      foo | bar | F
      

      正如您从约束违反错误消息中看到的那样,这是根据 Firebird 的底层触发机制实现的。

      【讨论】:

      • 在 MS SQL 上,我收到以下错误:Subqueries are not allowed in this context. Only scalar expressions are allowed.
      猜你喜欢
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多