MySQL中的CHECK约束不起作用


126

首先我创建了一个像

CREATE TABLE Customer (
  SD integer CHECK (SD > 0),
  Last_Name varchar (30),
  First_Name varchar(30)
);

然后在该表中插入值

INSERT INTO Customer values ('-2','abc','zz');

MySQL没有显示错误,它接受了值。


部分同意。考虑到您尝试使用它,可以假设您在问两个问题。实际上,您接受的答案主要是解释为什么它不起作用。
igorrs

1
您可以对此功能请求进行投票:bugs.mysql.com/bug.php?id=3464,但是十年来一直没有得到任何关注。
杰瑞德·贝克

11
您可以从10.2.1版开始在MariaDB中使用CHECK约束。
joanq

Answers:


140

MySQL 8.0.16是第一个支持CHECK约束的版本。

阅读https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html

如果您使用MySQL 8.0.15或更早版本,则MySQL参考手册会指出:

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 ;

希望有帮助。


9
在这里,您将找到如何触发错误的方法:stackoverflow.com/a/7189396/1144966
petermeissner,2013年

41
出于种种原因,这是我可以选择使用PostgreSQL而不是MySQL的巨大原因。
Reinderien

5
我想知道如果解析器遇到CHECK定义的约束,在MySQL中开发10分钟还是15分钟才能发出警告。啊,那太简单了……
gaborsch 2016年

75

不幸的是,MySQL不支持SQL检查约束。您可以出于兼容性原因在DDL查询中定义它们,但它们只会被忽略。

有一个简单的选择

您可以创建BEFORE INSERTBEFORE 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设置为字段默认值,对于id而言实际上没有意义tho

编辑: 删除了流浪报价。

关于:=运营商:

不同于=:=运算符永远不会被解释为比较运算符。这意味着您可以:=在任何有效的SQL语句中(不仅在SET语句中)使用来为变量分配值。

https://dev.mysql.com/doc/refman/5.6/zh-CN/assignment-operators.html

关于反引号标识符引号:

标识符引号是反引号(“`”)

如果启用了ANSI_QUOTES SQL模式,则也允许在双引号中引起标识符

http://dev.mysql.com/doc/refman/5.6/en/identifiers.html


7
...不是很简单,在比较,以检查:(弄点tutes至少:net.tutsplus.com/tutorials/databases/...sitepoint.com/how-to-create-mysql-triggers

嗯,这看起来很笨重。我想我宁愿在python中创建一个元组并在其中检查值,而不是将其放入其中
。– OzzyTheGiant

快速提问:为什么不设置则无法使用DELIMITER
ddz

52

CHECK MySQL会忽略约束,如文档中的小注释中所述: CREATE TABLE

CHECK子句已解析,但所有存储引擎均将其忽略。


2
@thefiloe:正确,在具有正确CHECK约束条件的其他DBMS中,如果CHECK求值不正确,则FALSE插入(或更新)操作未完成,并导致错误。
ypercubeᵀᴹ

已在MariaDB中修复(请参阅此答案stackoverflow.com/a/44333349)。
杰罗姆'18

@Jérôme我知道,我有一些(最近的)答案,其中包括对此领域的改进(在MariaDB和MySQL正确实施CHECK约束之前,还有其他方法可以解决此问题,包括MariaDB和MySQL)。我不确定是否应该去编辑所有旧答案!
ypercubeᵀᴹ

我想我的评论带有最近回答的链接是可以的。还是总比没有好。也许我应该编辑。我不是要给你施加压力去做任何事情。
杰罗姆



1

自版本8.0.15起支持检查约束(尚未发布)

https://bugs.mysql.com/bug.php?id=3464

[1月23日16:24] Paul Dubois

开发者发布:在8.0.15中修复。

以前,MySQL允许使用有限形式的CHECK约束语法,但会对其进行分析和忽略。MySQL现在为所有存储引擎实现了表和列CHECK约束的核心功能。使用CREATE TABLE和ALTER TABLE语句定义约束。


1

更新至MySQL 8.0.16以使用checks

从MySQL 8.0.16开始,CREATE TABLE允许所有存储引擎的表和列CHECK约束的核心功能。对于表约束和列约束,CREATE TABLE允许以下CHECK约束语法

MySQL检查文档


-2

尝试使用set sql_mode = 'STRICT_TRANS_TABLES'ORSET sql_mode='STRICT_ALL_TABLES'


2
实际无济于事(MySQL 5.6)它可以防止输入错误类型的数据,但不能输入不符合CHECK约束条件的数据
petermeissner 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.