有趣的特性:CHECK约束
有趣的特性:CHECK约束
功能说明
在MySQL 8.0.16以前, CREATE TABLE允许从语法层面输入下列CHECK约束,但实际没有效果:
CHECK (expr)
在 MySQL 8.0.16,CREATE TABLE添加了针对所有存储引擎的表和列的CHECK约束的核心特性。CREATE TABLE允许如下针对表或列的约束语法:
[CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]
- 可选的
symbol指定了约束的名称,如果省略,MySQL会自动生成一个类似:${table_name}_check_${seq_num}的约束名称,约束名称是大小写敏感的,且最长可以到64个字符
expr设定了一个返回值为boolean类型的约束条件,表达式对所有的数据行评估的结果值为:TRUE或UNKNOWN(对NULL值),当值为FALSE时,约束就被违反,产生的效果与执行的语句有关可选的执行子句标识约束是否需要被强制:
当未指定或指定为:
ENFORCED时,约束被创建且生效当指定为:
NOT ENFORCED时,约束被创建但未生效
一个
CHECK约束可以被指定为表约束或列约束表约束不会出现在列定义内,可以引用任意多个或一个列,且允许引用后续定义的表列
列约束出现在列定义内,仅允许引用该列
示例如下:
CREATE TABLE t1
(
CHECK (c1 <> c2),
c1 INT CHECK (c1 > 10),
c2 INT CONSTRAINT c2_positive CHECK (c2 > 0),
c3 INT CHECK (c3 < 100),
CONSTRAINT c1_nonzero CHECK (c1 <> 0),
CHECK (c1 > c3)
);
以上示例包含了列约束和表约束,命名和未命名的格式:
第一个约束是一个不包含在任何列定义内的表约束,所以允许引用任意列,且引用了后续定义的列,同时没有给出约束名称,所以MySQL会给该约束生成一个名字
后续的3个约束是包含在列定义内的列约束,所有指定引用所在的列
最后的两个是表约束
如果想查看上述命令所生成的约束名,可以输入以下SHOW CREATE TABLE命令:
mysql> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`c1` int(11) DEFAULT NULL,
`c2` int(11) DEFAULT NULL,
`c3` int(11) DEFAULT NULL,
CONSTRAINT `c1_nonzero` CHECK ((`c1` <> 0)),
CONSTRAINT `c2_positive` CHECK ((`c2` > 0)),
CONSTRAINT `t1_chk_1` CHECK ((`c1` <> `c2`)),
CONSTRAINT `t1_chk_2` CHECK ((`c1` > 10)),
CONSTRAINT `t1_chk_3` CHECK ((`c3` < 100)),
CONSTRAINT `t1_chk_4` CHECK ((`c1` > `c3`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
SQL规范要求:所有约束(包括:PRIMARY KEY, UNIQUE,FOREIGN KEY, CHECK)属于同一个命名空间(NAMESPACE),在MySQL实现中,所有的约束类型在每个schema (database)内有自己的命名空间。所以,CHECK约束的名称在SCHEMA内必须唯一,也就是说不允许有两张表使用同一个CHECK约束名称。(例外:一个临时表可能使用与非临时表一样的约束名称)
CHECK的条件表达式必须遵守以下规则,如果包含不允许的结构,将会触发错误:
非生成列和生成列允许被添加到表达式,但包含
AUTO_INCREMENT属性的列和其他表的列不允许被加入字面量和确定性(deterministic)的内置函数以及操作符允许被添加到表达式,确定性的含义是:同样的数据不同用户的多次调用的结果是一致的,非确定性的函数包括:
CONNECTION_ID(),CURRENT_USER(),NOW()存储函数和用户自定义函数不被允许
存储过程不被允许
变量:系统变量、用户自定义变量和存储过程的本地变量均不被允许使用
子查询不应许被使用
外键参考动作,如:
ON UPDATE,ON DELETE被禁止在包含CHECK约束的列使用,相应的,CHECK约束也被禁止在使用外键参考动作的列使用CHECK约束在插入、更新、替换(REPLACE)和LOAD DATA/XML语句的时候被评估,如果评估结果是FALSE将触发错误,如果错误发生,已经提交的数据的处理与对应存储引擎是否支持事务有关,也依赖严格SQL模式是否生效如果约束表达式所需的数据类型与声明的列类型不一致,数据将参考MySQL的类型转换规则被隐式的转换
约束表达式在不同的SQL模式下,可能返回不同的结果
另外,在INFORMATION_SCHEMA的CHECK_CONSTRAINTS表中存放着所有表中定义的CHECK约束的信息。
建议使用CHECK约束的场景
复杂业务场景下的约束,从架构角度看,允许有不同的实现方式:
放在数据库表中,通过约束实现,但不支持子查询
放在数据库中,通过触发器(TRIGGER)实现
放在应用程序的逻辑中,在提前数据库前检查
一般性的,选择不同方式的原则如下:
- 如果CHECK约束可以实现,且约束比较稳定,一般用CHECK约束实现,比如:年龄不允许为负数,不允许>150等,比如:
CREATE TABLE Departments (
ID int NOT NULL,
PID int NOT NULL,
Name varchar(255) NOT NULL Default '',
CHECK (ID>=1)
);
-- add check separately
ALTER TABLE Departments
ADD CONSTRAINT CHK_PID CHECK (ID>=1 AND PID >=0);
-- remove check
ALTER TABLE Departments
DROP CHECK CHK_PID;
- 如果属于数据库逻辑,比如:审计,外键可以使用触发器
CREATE TABLE IF NOT EXISTS `department` (
`id` int NOT NULL AUTO_INCREMENT,
`pid` int COMMENT 'parent id',
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB;
CREATE TRIGGER pid_insert_check
BEFORE INSERT ON department
FOR EACH ROW
BEGIN
IF (NEW.pid <> 0 AND NEW.pid NOT IN (select id from department)) THEN
signal sqlstate '45000'
set message_text = 'department parent id has to be chosen from id';
END IF;
END
CREATE TRIGGER pid_delete_check
BEFORE DELETE ON department
FOR EACH ROW
BEGIN
IF (OLD.id < 0 OR OLD.id IN (select pid from department)) THEN
signal sqlstate '45000'
set message_text = 'department parent id has to be chosen from id';
END IF;
END
- 如果属于业务逻辑,建议放在应用层处理,方便开发者:理解和维护,但是:也需要通过强化业务管理,避免特权用户偶发操作引起对数据完整性的破坏
Enjoy GreatSQL
文章推荐:
Changes in GreatSQL 8.0.25 (2021-8-18)
关于 GreatSQL
GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。
Gitee:
https://gitee.com/GreatSQL/GreatSQL
GitHub:
https://github.com/GreatSQL/GreatSQL
Bilibili:
https://space.bilibili.com/1363850082/favlist
微信&QQ群:
QQ群:533341697
微信群:可搜索添加GreatSQL社区助手微信好友,发送验证信息“加群”加入GreatSQL/MGR交流微信群
GreatSQL社区助手:wanlidbc
有趣的特性:CHECK约束的更多相关文章
- MariaDB10.2.X-新特性2-支持check约束and with as
前几天写了一篇MariaDB10.2支持分析函数,大家印象中MySQL不支持with as ,check约束,那么MariaDB10.2也同样给你惊喜 1.with as MariaDB [test1 ...
- SQL Server中使用Check约束提升性能
在SQL Server中,SQL语句的执行是依赖查询优化器生成的执行计划,而执行计划的好坏直接关乎执行性能. 在查询优化器生成执行计划过程中,需要参考元数据来尽可能生成高效的执行计划, ...
- SQL PRIMARY KEY 约束\SQL FOREIGN KEY 约束\SQL CHECK 约束
SQL PRIMARY KEY 约束 PRIMARY KEY 约束唯一标识数据库表中的每条记录. 主键必须包含唯一的值. 主键列不能包含 NULL 值. 每个表都应该有一个主键,并且每个表只能有一个主 ...
- oracle之check约束小结
一下是Ocp考试指导中,对于oracle约束的描述: The constraint types supported by the Oracle database are as follows:UNIQ ...
- oracle 序列 ,check约束
====================序列 //查询当前用户序列 select * from user_sequences //查询所有序列 select * from all_sequences; ...
- Oracle之Check约束实例具体解释
Oracle | PL/SQL Check约束使用方法具体解释 1. 目标 实例解说在Oracle中怎样使用CHECK约束(创建.启用.禁用和删除) 2. 什么是Check约束? CHECK约束指在表 ...
- MySQL关于check约束无效的解决办法
首先看下面这段MySQL的操作,我新建了一个含有a和b的表,其中a用check约束必须大于0,然而我插入了一条(-2,1,1)的数据,其中a=-2,也是成功插入的. 所以MySQL只是check,但是 ...
- SQLServer之修改CHECK约束
使用SSMS数据库管理工具修改CHECK约束 1.打开数据库,选择数据表->右键点击->选择设计(或者展开约束,选择约束,右键点击,选择修改,后面步骤相同). 2.选择要修改的数据列-&g ...
- SQLServer之CHECK约束
CHECK约束添加规则 1.CHECK 约束用于限制列中的值的范围. 2.Check约束通过逻辑表达式来判断数据的有效性,用来限制输入一列或多列的值的范围,在列中更新数据时,所要输入的内容必须满足Ch ...
随机推荐
- 什么!Sentinel流控规则可以这样玩?
项目源码地址:公众号回复 sentinel,即可免费获取源码 前言 上一篇文章中,我们讲解了关于sentinel基本介绍以及流控规则中直接和快速失败的效果,有兴趣的可以去看上一篇文章,今天,我们给大家 ...
- 关于SpringBoot Admin server 监控注意事项
当你导入了依赖 <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-bo ...
- JOISC2020 题解
Day1T1 建筑装饰4 题目链接:Day1T1 建筑装饰4 Solution 我们先考虑朴素的\(dp\)方法: 设\(dp_{i,j,k}\)表示前\(i\)个数中,选了\(j\)个\(B\)数组 ...
- git 无法拉取最新代码
删除本地文件后,想从远程仓库中重新新Pull最新代码,但是执行了git pull origin develop 命令后始终无法拉取下来 提示 Already up-to-date. 原因:当前本地库处 ...
- 洛谷 P2629 好消息,坏消息 题解
暴力算法的时间复杂度是O(n^2),考虑优化: 先导入一种思想--断环为链.说通俗点就是在原数组后面再接上下标为1--(n - 1)的元素: 以样例为例:-3 5 1 2:我们将其断环为链后可以得到这 ...
- 快速 IO
IO 的进化史 cin和cout 刚开始学的时候,老师叫我们用 cin 和 cout 大概是因为这最简单吧 cin>>x; cout<<x scanf和printf 学到函数了 ...
- 线程安全性-原子性之synchronized锁
原子性提供了互斥访问:同一时刻只能有一个线程进行操作: 除了Atomic包类之外,还有锁可以实现此功能: synchronized: java关键字,依赖于jvm实现锁功能,被此关键字所修饰的,都是 ...
- Camunda定时器事件示例Demo(Timer Events)
Camunda定时器事件(Timer Events)是由定义的计时器触发的事件.它们可以用作启动事件.中间事件或边界事件.边界事件可以中断,也可以不中断. Camunda定时器事件包括:Timer ...
- 推荐一款M1芯片电脑快速搭建集群的虚拟机软件
虚拟机软件太多了,出名的莫过于VMware,VirutlaBox以及Parallels Desktop. 我们使用虚拟机软件一般有两种用途: 安装不同于宿主机系统的拥有用户界面的操作系统,比如Wind ...
- Python爬取某网站文档数据完整教程(附源码)
基本开发环境 (https://jq.qq.com/?_wv=1027&k=NofUEYzs) Python 3.6 Pycharm 相关模块的使用 (https://jq.qq.com/?_ ...