列约束fk_列级约束和元组级约束的区别

列约束fk_列级约束和元组级约束的区别check 约束意思,就是对一列或者多列按照一定的预先设置好的规则进行过滤,条件为真,则过滤成功;条件为假,则过滤失败,返回失败代码给客户端。 为什么要把这个单独列出来写呢,经常遇到不规范的 SQL…

第04期:列 CHECK 约束

check 约束意思,就是对一列或者多列按照一定的预先设置好的规则进行过滤,条件为真,则过滤成功;条件为假,则过滤失败,返回失败代码给客户端。

为什么要把这个单独列出来写呢,经常遇到不规范的 SQL,很多时候只能靠数据库层来过滤,代码端不过滤,就只能在数据库端过滤了。

一、常见过滤方式

假设表 f1,字段 r1 类型为 3 的倍数,否则拒绝写入。又假设 r1 的输入不规范,只能靠数据库来过滤,那怎么办?无非有几种:

1)写前置触发器

示例 1

mysql> create table f1 (r1 int);
Query OK, 0 rows affected (0.03 sec)

DELIMITER $

USE `ytt`$

DROP TRIGGER /*!50032 IF EXISTS */ `tr_check_f1_r1`$

CREATE
/*!50017 DEFINER = "root"@"%" */
TRIGGER `tr_check_f1_r1` BEFORE INSERT ON `f1
FOR EACH ROW BEGIN
IF MOD(new.r1,3) <> 0 THEN
SIGNAL SQLSTATE "45000"
SET MESSAGE_TEXT = "Column r1 should be mod by 3,failed to insert.";
END IF;
END;
$
DELIMITER ;

代码100分

执行下,暴露出异常

代码100分mysql> insert into f1 values (5);
ERROR 1644 (45000): Column r1 should be mod by 3,failed to insert.

正常插入

mysql> insert into f1 values (3);
Query OK, 1 row affected (0.01 sec)

mysql> select * from f1;
+------+
| r1   |
+------+
|    3 |
+------+
1 row in set (0.00 sec)

以上例子简单针对了单列过滤的场景,多列复杂的过滤后面再说。

2)写存储过程封装 SQL

在存储过程里处理输入约束,和在程序端处理输入约束逻辑一致,只是把相同的处理逻辑放在数据库端,并且以后所有对数据的录入只能依赖存储过程单一入口。

3)不拒绝任何输入,定期处理不规范数据

这样会导致录入的数据量非常大,存在很多无用的不规范数据,一般选择非业务高峰时段定期处理不规范数据。

这两种就不举例子了,和第一种类似的处理方法。

二、CHECK 约束

现在要说的是在列这一层次过滤的基于表定义之前就规范好的 CHECK 约束。(MySQL 版本 >= 8.0.16)

代码100分mysql> create table f1 (r1 int constraint tb_f1_r1_chk1 check (mod(r1,3)=0));
Query OK, 0 rows affected (0.03 sec)

mysql> create table f2 (r1 int constraint tb_f2_r1_chk1 check (mod(r1,3)=0) not enforced);
Query OK, 0 rows affected (0.02 sec)

这里 CHECK 约束的相关限制如下:

  1. constraint 名字在每个数据库中唯一。

也就是说单个数据库里不存在相同的两个 constraint,如果不定义,系统自动生成一个唯一的约束名字。

  1. check 约束针对语句 insert/update/replace/load data/load xml 生效;针对对应的 ignore 语句失效。

  2. 并非每个函数都可以使用,比如函数结果不确定的:NOW(),CONNECTION_ID(),CURRENT_USER()。

  3. 不适用于存储过程和存储函数。

  4. 系统变量不适用。

  5. 子查询不适用。

  6. 外键动作(比如 ON UPDATE, ON DELETE) 不适用。

  7. enforced 默认启用,如果单独加上 not enforced ,check 约束失效。

示例 2

结合以上看看刚才那两张表实际的例子,check 约束仅仅对表 f1 生效。

mysql> insert into f1 values (10);
ERROR 3819 (HY000): Check constraint "tb_f1_r1_chk1" is violated.
mysql> insert into f2 values (10);
Query OK, 1 row affected (0.01 sec)

mysql> select * from f1
Empty set (0.00 sec)

mysql> select  * from f2;
+------+
| r1   |
+------+
|   10 |
+------+
1 row in set (0.00 sec)

接下来看看 CHECK 约束更加详细的例子。

示例 3

mysql> drop table f1;
Query OK, 0 rows affected (0.02 sec)

mysql> create table f1
-> (
->  r1 int constraint tb_f1_r1_chk1 check (r1 > 10),
->  r2 int constraint tb_f1_r2_positive check (r2 > 0),
->  r3 int constraint tb_f1_r3_chk1 check (r3 < 100),
->  constraint tb_f1_r1_nonzero check (r1 <> 0),
->  constraint tb_f1_r1r2_chk1 check (r1 <> r2),
->  constraint tb_f1_r1r3_chk1 check (r1 > r3)
-> );
Query OK, 0 rows affected (0.02 sec)

上面例子有一点说明下,

  1. 约束tb_f1_r1_nonzero、tb_f1_r1r2_chk1、tb_f1_r1r3_chk 不跟随固定的列,对全局有效,也可以说基于表的 check 约束。

  2. 约束tb_f1_r1_chk1 包含 约束 tb_f1_r1_nonezero, 这样 tb_f1_r1_nonezero 永远探测不到异常。所以检查后,去掉这个约束。

拿掉多余的约束后的定义,

mysql> create table f1
-> (
->  r1 int constraint tb_f1_r1_chk1 check (r1 > 10),
->  r2 int constraint tb_f1_r2_positive check (r2 > 0),
->  r3 int constraint tb_f1_r3_chk1 check (r3 < 100),
->  constraint tb_f1_r1r2_chk1 check (r1 <> r2),
->  constraint tb_f1_r1r3_chk1 check (r1 > r3)
-> );
Query OK, 0 rows affected (0.02 sec)

那针对这张表做个测试,可以看到这里每个列的约束其实是“与”的关系,任何一列约束不成立写入就失败。

mysql> insert into f1 values (20,10,10);
Query OK, 1 row affected (0.01 sec)

mysql> insert into f1 values (10,10,10);
ERROR 3819 (HY000): Check constraint "tb_f1_r1_chk1" is violated.
mysql> insert into f1 values (20,-10,10);
ERROR 3819 (HY000): Check constraint "tb_f1_r2_positive" is violated.
mysql> insert into f1 values (20,10,30);
ERROR 3819 (HY000): Check constraint "tb_f1_r1r3_chk1" is violated.

那接下来我们改造刚开始那个触发器,只要把相关条件加进去就可以实现同样的 check 列约束。

DELIMITER $

USE `ytt`$

DROP TRIGGER /*!50032 IF EXISTS */ `tr_check_f1_r1`$

CREATE
/*!50017 DEFINER = "root"@"%" */
TRIGGER `tr_check_f1_r1` BEFORE INSERT ON `f1`
FOR EACH ROW BEGIN
DECLARE v1 TINYINT DEFAULT 0;

IF (new.r1 > 10 AND new.r1 > new.r3 AND new.r1 <> new.r2 AND new.r2 > 0 AND new.r3 < 100) = 0 THEN
SIGNAL SQLSTATE "45000"
SET MESSAGE_TEXT = "Failed to write: constraint check: 
 (
 r1 >10 
&&  r1 > r3 
&& r1 <> r2 
&& r2> 0 
&& r3 < 100
).";
END IF;
END;
$

DELIMITER ;

测试下效果,

mysql> insert into f1 values (20,30,100);
ERROR 1644 (45000): Failed to write: constraint check:
(
r1 >10
&&  r1 > r3
&& r1 <> r2
&& r2> 0
&& r3 < 100
).

mysql> insert into f1 values (100,30,90);
Query OK, 1 row affected (0.01 sec)

mysql> select * from f1;
+------+------+------+
| r1   | r2   | r3   |
+------+------+------+
|  100 |   30 |   90 |
+------+------+------+
1 row in set (0.00 sec)

结论

本文介绍了数据库 CHECK 约束相关的用法以及大概例子。

我个人建议,这种 CHECK 约束如果能从数据库端剥离放到应用端实现最好不过了,数据端越简单,性能越好。但也有例外,应用端如果由于历史原因或者其他因素实现困难,也只能寄于数据库端。


关于 MySQL 的技术内容,你们还有什么想知道的吗?赶紧留言告诉小编吧! 列约束fk_列级约束和元组级约束的区别

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/8472.html

(0)
上一篇 2023-02-27
下一篇 2023-02-27

相关推荐

  • kapacitor的安装及部分常用命令

    kapacitor的安装及部分常用命令Kapacitor 是一个开源框架,用来处理、监控和警告时间序列数据,它使用 TICKscript 脚本来定义任务。Kapacitor是InfluxData开源的数据处理引擎。它可

    2023-04-16
    156
  • 使用setuptools进行Python包安装

    使用setuptools进行Python包安装在Python开发过程中,我们经常需要使用第三方库。而安装这些库需要保证正确的依赖关系和版本选择,这可能会导致一些问题。setuptools是一个流行的Python包管理工具,它可以自动解决依赖关系并为您管理包的版本。它还可以轻松地构建和分发您自己的Python包。在本文中,我们将介绍如何使用setuptools来安装和管理Python包。

    2024-09-03
    12
  • Python当前路径

    Python当前路径在Python中,获取当前路径是非常常见的操作。当前路径指的是执行Python脚本时,操作系统所处的路径,也称为工作目录。

    2024-05-29
    52
  • Omnidb[通俗易懂]

    Omnidb[通俗易懂]Omnidb 下载Server版本RPM即可: https://omnidb.org/en/downloads-en 正常启动是这样: omnidb-server -H 0.0.0.0 -p 933…

    2023-04-12
    178
  • MySQL快速回顾:高级查询操作「建议收藏」

    MySQL快速回顾:高级查询操作「建议收藏」8.1 排序数据 检索出的数据并不是以纯粹的随机顺序显示的。如果不排序,数据一般将以它在底层表中出现的顺序显示。这可以是数据最初添加到表中的顺序。但是,如果数据后来进行过更新或删除,则此顺序将会受到M

    2023-01-23
    139
  • Python 字典:非重复键值对存储方式的利器

    Python 字典:非重复键值对存储方式的利器Python 字典是一种非常强大的数据类型,它可以用于存储非重复的键值对。它使用哈希表来实现,在时间复杂度为O(1)的情况下,可以完成以下操作:

    2024-04-08
    61
  • flask_16:通过 MongoEngine 使用 MongoDB

    flask_16:通过 MongoEngine 使用 MongoDB
    使用一个 MongoDB 之类的文档型数据库来代替关系 SQL 数据是很常见的。本方案演示 如何使用文档映射库 MongoEngine 来集成 MongoD…

    2023-04-05
    166
  • Python中如何处理年龄数据

    Python中如何处理年龄数据年龄数据是数据科学中非常重要的数据类型之一。在机器学习的模型中,年龄数据也经常被作为一个特征来使用。但是,年龄数据并不像其他数据类型那样直接可用,需要进行一些处理和转换。本文将从多个方面详细介绍Python中如何处理年龄数据。

    2024-03-19
    82

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注