MySQL 中的 CHECK 约束不起作用
Posted
技术标签:
【中文标题】MySQL 中的 CHECK 约束不起作用【英文标题】:CHECK constraint in MySQL is not working 【发布时间】:2011-01-08 02:24:03 【问题描述】:首先我创建了一个类似的表
CREATE TABLE Customer (
SD integer CHECK (SD > 0),
Last_Name varchar (30),
First_Name varchar(30)
);
然后在该表中插入值
INSERT INTO Customer values ('-2','abc','zz');
mysql 没有显示错误,它接受了这些值。
【问题讨论】:
部分同意。鉴于您尝试使用它,可以假设您同时问了这两个问题。其实你接受的答案主要是解释为什么不行。 您可以对此功能请求投票:bugs.mysql.com/bug.php?id=3464,但十年来没有受到任何关注。 您可以在 MariaDB 中使用来自version 10.2.1 的 CHECK 约束。 现在 MySQL 8.0.16 终于解决了这个问题,是时候默默地认识到(!)也忽略了内联 REFERENCES 规范(另一个大的 SQL 标准不兼容):bugs.mysql.com/bug.php?id=102904。 在 MySQL 8.x 中存在 CHECK CONSTRAINT 支持 【参考方案1】:CHECK
约束似乎没有在 MySQL 中实现。
查看此错误报告:https://bugs.mysql.com/bug.php?id=3464
【讨论】:
已在 MariaDB 中修复(请参阅此答案 ***.com/a/44333349)。【参考方案2】:MySQL 8.0.16 是第一个支持 CHECK 约束的版本。
阅读https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html
如果您使用 MySQL 8.0.15 或更早版本,MySQL Reference Manual 表示:
CHECK
子句被解析,但被所有存储引擎忽略。
试试触发器...
mysql> delimiter //
mysql> CREATE TRIGGER trig_sd_check BEFORE INSERT ON Customer
-> FOR EACH ROW
-> BEGIN
-> IF NEW.SD<0 THEN
-> SET NEW.SD=0;
-> END IF;
-> END
-> //
mysql> delimiter ;
希望对您有所帮助。
【讨论】:
这里您将了解如何触发错误:***.com/a/7189396/1144966 这是我将始终使用 PostgreSQL 而不是 MySQL 的众多原因之一。 我想知道如果解析器遇到定义的CHECK
约束,是否会在 MySQL 中开发 10 分钟或 15 分钟来引发警告。啊,那太简单了……【参考方案3】:
试试set sql_mode = 'STRICT_TRANS_TABLES'
或SET sql_mode='STRICT_ALL_TABLES'
【讨论】:
这实际上没有帮助(MySQL 5.6)它可以防止输入错误类型的数据,但不能输入不符合CHECK
约束的数据【参考方案4】:
CHECK
约束被 MySQL 忽略,如文档中的小评论中所述:CREATE TABLE
CHECK
子句被解析,但被所有存储引擎忽略。
【讨论】:
@thefiloe: 正确,在正确实现CHECK
约束的其他DBMS 中,如果CHECK
评估为FALSE
,则插入(或更新)未完成并导致错误.
已在 MariaDB 中修复(请参阅此答案 ***.com/a/44333349)。
@Jérôme 我知道,我有一些(更新的)答案,其中包括该领域的改进(在 MariaDB 正确实施 CHECK 约束之前,在 MariaDB 和 MySQL 中都有其他解决此问题的方法)。我不确定我是否应该去编辑我所有的旧答案!
我想我的评论带有一个更新的答案的链接是好的。或者总比没有好。也许我应该编辑。我并不是要强迫你做任何事情。【参考方案5】:
不幸的是 MySQL 不支持 SQL 检查约束。出于兼容性原因,您可以在 DDL 查询中定义它们,但它们会被忽略。
有一个简单的替代方案
您可以创建BEFORE INSERT
和BEFORE UPDATE
触发器,当不满足数据要求时,它们会导致错误或将字段设置为其默认值。
BEFORE INSERT
在 MySQL 5.5 之后工作的示例
DELIMITER $$
CREATE TRIGGER `test_before_insert` BEFORE INSERT ON `Test`
FOR EACH ROW
BEGIN
IF CHAR_LENGTH( NEW.ID ) < 4 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT := 'check constraint on Test.ID failed';
END IF;
END$$
DELIMITER ;
在 MySQL 5.5 之前,您必须导致错误,例如调用未定义的过程。
在这两种情况下,这都会导致隐式事务回滚。 MySQL 不允许 ROLLBACK 语句本身在过程和触发器中。
如果您不想回滚事务(即使“检查约束”失败,INSERT / UPDATE 也应该通过,您可以使用 SET NEW.ID = NULL
覆盖该值,这会将 id 设置为字段默认值,不会对于一个身份来说真的很有意义
编辑: 删除了杂散引用。
关于:=
运算符:
与
=
不同,:=
运算符永远不会被解释为比较运算符。这意味着您可以在任何有效的 SQL 语句(不仅仅是在 SET 语句中)使用:=
为变量赋值。
https://dev.mysql.com/doc/refman/5.6/en/assignment-operators.html
关于反引号标识符引号:
标识符引号字符是反引号(“`”)
如果启用了 ANSI_QUOTES SQL 模式,也允许在双引号内引用标识符
http://dev.mysql.com/doc/refman/5.6/en/identifiers.html
【讨论】:
...不是很简单,至少与 CHECK 相比 :(。Coupla tutes: net.tutsplus.com/tutorials/databases/…, sitepoint.com/how-to-create-mysql-triggers 呃,这看起来很笨重。我想我宁愿在 python 中创建一个元组并在那里检查值而不是把它放进去。 快速提问:为什么不设置DELIMITER
就行不通?
但是为什么呢?我的意思是,他们可能只是删除了该命令。保留命令并删除其功能有什么意义?
该命令是在 Mysql 遵循的 SQL 的 ANSI 标准中定义的。 dev.mysql.com/doc/refman/8.0/en/compatibility.html【参考方案6】:
正如 joanq MariaDB 所提到的,现在似乎支持 CHECK 约束以及其他好东西:
“支持检查约束 (MDEV-7563)。”
https://mariadb.com/kb/en/mariadb/mariadb-1021-release-notes/
【讨论】:
【参考方案7】:从 8.0.15 版开始支持检查约束(尚未发布)
https://bugs.mysql.com/bug.php?id=3464
[1 月 23 日 16:24] 保罗·杜布瓦
开发者发布:已在 8.0.15 中修复。
以前,MySQL 允许有限形式的 CHECK 约束语法, 但解析并忽略了它。 MySQL 现在实现了 表和列 CHECK 约束,适用于所有存储引擎。 约束是使用 CREATE TABLE 和 ALTER TABLE 语句定义的。
【讨论】:
【参考方案8】:更新到 MySQL 8.0.16 以使用checks
:
从 MySQL 8.0.16 开始,CREATE TABLE 允许 table 的核心功能 和列 CHECK 约束,适用于所有存储引擎。创建表 允许以下 CHECK 约束语法,对于两个表 约束和列约束
MySQL Checks Documentation
【讨论】:
以上是关于MySQL 中的 CHECK 约束不起作用的主要内容,如果未能解决你的问题,请参考以下文章