【发布时间】:2011-01-06 17:43:44
【问题描述】:
我想将BOOLEAN 列添加到名为is_default 的MySQL 表中。在此列中,只有一条记录可以将is_default 设置为true。
如何使用 MySQL 将此约束添加到我的列?
谢谢!
更新
如果不是我应该添加的约束。我们如何处理 DB 上的此类问题?
【问题讨论】:
标签: sql mysql constraints
我想将BOOLEAN 列添加到名为is_default 的MySQL 表中。在此列中,只有一条记录可以将is_default 设置为true。
如何使用 MySQL 将此约束添加到我的列?
谢谢!
更新
如果不是我应该添加的约束。我们如何处理 DB 上的此类问题?
【问题讨论】:
标签: sql mysql constraints
在 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!
【讨论】:
我们如何处理 DB 上的此类问题?
在某些 DBMS 中,您可以创建部分索引。
在 PostgreSQL 中,这看起来像这样:
仅创建唯一索引_one_true ON the_table (is_default) WHERE is_defaultSQL Server 2008 的语法非常相似。
在 Oracle 上它有点复杂但也可行:
仅创建唯一索引_one_true 在 the_table 上(案例 当 is_default = 1 那么 1 否则为空 结尾)Oracle 解决方案可能适用于任何支持索引定义表达式的 DBMS。
【讨论】:
我认为这不是数据库的问题,而是您的模型的问题。我很难想出一个很好的例子来说明如何解决它,因为你没有提到你代表的是什么类型的数据,但是 XXXType 或 XXXConfiguration 表可以容纳 defaultXXXId柱子。
这样想:color blue 是否应该知道它是默认的,或者其他东西是否应该知道 color blue 在给定上下文中使用时是默认的?
更改数据建模方式通常是一种更好的跨数据库兼容性方法,而不是尝试使用一种数据库风格的特定功能以一种对您的问题领域来说不一定自然的方式来表示数据它。
【讨论】:
检查触发器。我相信它们是在 5.0.2 版中引入的。您想要一个“插入前”触发器。如果已经存在 is_default=true 的行,则引发错误。我不知道您在并发等方面可能会遇到什么问题,但希望这对您来说已经足够了。
【讨论】:
我认为这不是对单个默认值的情况进行建模的最佳方式。
相反,我将忽略 IsDefault 列并创建一个单独的表,其中包含一行,并且仅包含构成主表主键的列。在此表中放置标识默认记录的 PK 值。
这会大大减少存储空间,并避免在更新时暂时没有默认值(或者,暂时有两个默认值)的更新问题。
您有许多选项来确保默认表中只有一行。
【讨论】:
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 假 */【讨论】: