【问题标题】:How to create a "unique" constraint on a boolean MySQL column?如何在布尔 MySQL 列上创建“唯一”约束?
【发布时间】:2011-01-06 17:43:44
【问题描述】:

我想将BOOLEAN 列添加到名为is_default 的MySQL 表中。在此列中,只有一条记录可以将is_default 设置为true

如何使用 MySQL 将此约束添加到我的列?

谢谢!


更新

如果不是我应该添加的约束。我们如何处理 DB 上的此类问题?

【问题讨论】:

    标签: sql mysql constraints


    【解决方案1】:

    在 MySQL 中不能有这样的约束。

    但是,如果您使用值 TRUE 和 NULL 而不是 TRUE 和 FALSE,那么它将起作用,因为 UNIQUE 列可以有多个 NULL 值。请注意,这并不适用于所有数据库,但它适用于 MySQL。

    CREATE TABLE table1(b BOOLEAN UNIQUE);
    
    INSERT INTO table1 (b) VALUES (TRUE);   // Succeeds
    INSERT INTO table1 (b) VALUES (TRUE);   // Fails: duplicate entry '1' for key 'b'
    
    INSERT INTO table1 (b) VALUES (FALSE);  // Succeeds
    INSERT INTO table1 (b) VALUES (FALSE);  // Fails: duplicate entry '0' for key 'b'
    
    INSERT INTO table1 (b) VALUES (NULL);   // Succeeds
    INSERT INTO table1 (b) VALUES (NULL);   // Succeeds!
    

    【讨论】:

    • 是否有适用于所有主要数据库的解决方案?
    • @benjisail:是的,我至少可以想到一种方法,但这是一个丑陋的黑客(甚至比我目前的答案更糟糕)所以我不确定我应该把它发布在如果你真的实现它!
    【解决方案2】:

    我们如何处理 DB 上的此类问题?

    在某些 DBMS 中,您可以创建部分索引。

    在 PostgreSQL 中,这看起来像这样:

    仅创建唯一索引_one_true ON the_table (is_default) WHERE is_default

    SQL Server 2008 的语法非常相似。

    在 Oracle 上它有点复杂但也可行:

    仅创建唯一索引_one_true 在 the_table 上(案例 当 is_default = 1 那么 1 否则为空 结尾)

    Oracle 解决方案可能适用于任何支持索引定义表达式的 DBMS。

    【讨论】:

      【解决方案3】:

      我认为这不是数据库的问题,而是您的模型的问题。我很难想出一个很好的例子来说明如何解决它,因为你没有提到你代表的是什么类型的数据,但是 XXXTypeXXXConfiguration 表可以容纳 defaultXXXId柱子。

      这样想:color blue 是否应该知道它是默认的,或者其他东西是否应该知道 color blue 在给定上下文中使用时是默认的?

      更改数据建模方式通常是一种更好的跨数据库兼容性方法,而不是尝试使用一种数据库风格的特定功能以一种对您的问题领域来说不一定自然的方式来表示数据它。

      【讨论】:

        【解决方案4】:

        检查触发器。我相信它们是在 5.0.2 版中引入的。您想要一个“插入前”触发器。如果已经存在 is_default=true 的行,则引发错误。我不知道您在并发等方面可能会遇到什么问题,但希望这对您来说已经足够了。

        【讨论】:

          【解决方案5】:

          我认为这不是对单个默认值的情况进行建模的最佳方式。

          相反,我将忽略 IsDefault 列并创建一个单独的表,其中包含一行,并且仅包含构成主表主键的列。在此表中放置标识默认记录的 PK 值。

          这会大大减少存储空间,并避免在更新时暂时没有默认值(或者,暂时有两个默认值)的更新问题。

          您有许多选项来确保默认表中只有一行。

          【讨论】:

          • 有哪些选项可以确保默认表中只有一行?
          • 我也想要这个问题的答案。
          • 有人能多解释一下这个答案吗?只有 1 行的表如何确保主表中只有 1 个默认行?这里提出的单行表与主表有何关系?会加入吗?
          【解决方案6】:

          MySQL 不支持检查约束,这是使用触发器的解决方案:

          如果不存在则创建表 myTable ( id int not null auto_increment 主键, is_default 位不为空 ) 引擎=innodb; 选择“创建触发器 tbi_myTable”; 如果存在 tbi_myTable,则删除触发器; 分隔符 // 创建触发器 tbi_myTable 在 myTable 上插入之前 对于每一行 开始 if (select count(1) from myTable where is_default=true) > 0 && NEW.is_default then -- Signal 仅在 5.6 及以上使用另一种方式引发错误:如果小于 5.6 SIGNAL SQLSTATE '50000' SET MESSAGE_TEXT = '不能在 myTable 中插入只允许 is_default 为 true 的一行!'; 万一; 结尾 // 分隔符; 插入 myTable (is_default) 值 (false); 插入 myTable (is_default) 值 (true); 插入 myTable (is_default) 值 (false); 插入 myTable (is_default) 值 (false); -- 这会产生错误 插入 myTable (is_default) 值 (true); 插入 myTable (is_default) 值 (false); 从我的表中选择 *; - 会给 /* id is_default 1 错误 2 对 3 错误 4 假 */

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多