个人笔记不保证正确。

数据类型是限制我们可以在表里存储什么数据的一种方法。不过,对于许多应用来说, 这种限制实在是太粗糙了。比如,一个包含产品价格的字段应该只接受正数。 但是没有哪种标准数据类型只接受正数。 另外一个问题是你可能需要根据其它字段或者其它行的数据来约束字段数据。比如, 在一个包含产品信息的表中,每个产品编号都应该只有一行。

对于这些问题,SQL 允许你在字段和表上定义约束。约束允许你对数据施加任意控制。 如果用户企图在字段里存储违反约束的数据,那么就会抛出一个错误。 这种情况同时也适用于数值来自默认值的情况。

1. 外键 FOREIGN KEY

外键约束声明一个字段(或者一组字段)的数值必须匹配另外一个表中出现的数值。

创建外键约束的前提是,该外键所在的表已经存在,并且外键必须是 UNIQUE 的。(主键默认 UNIQUE 且 NOT NULL)

CREATE TABLE <表名> (
<字段名> <类型> PRIMARY KEY,
<字段名> <类型> REFERENCES <外键所在的表名> (<字段名>), -- 这创建了一个外键
...
);

还有另一种语法,它支持以多个字段为外键(字段约束也可以写成表约束,也就是放在一个独立的行中。而反过来很可能不行):

CREATE TABLE <表名> (
<字段名1> <类型> PRIMARY KEY,
<字段名2> <类型>
<字段名3> <类型>
...
FOREIGN KEY (<字段名2>, <字段名3>) REFERENCES <外键所在的表名> (<字段名4>, <字段名5>)
);

一个表也可以包含多个外键约束。这个特性用于实现表之间的多对多关系。 比如你有关于产品和订单的表,但现在你想允许一个订单可以包含多种产品 (上面那个结构是不允许这么做的),你可以使用这样的结构:

CREATE TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
); CREATE TABLE orders (
order_id integer PRIMARY KEY,
shipping_address text,
...
); CREATE TABLE order_items (
product_no integer REFERENCES products,
order_id integer REFERENCES orders,
quantity integer,
PRIMARY KEY (product_no, order_id)
);

外键能通过 ALTER 语句添加或删除

2. 级联操作 ON DELETEON UPDATE

上面说过:外键约束声明一个字段(或者一组字段)的数值必须匹配另外一个表中出现的数值。

但是以 1. 中最后一个 sql 为例,如果一个订单(order)在创建之后,该订单包含的某个产品(product)被删除了,会发生什么?

这个例子中,订单包含的产品通过外键被记录在 order_items 表中。现在如果你要删除 product 中某个被 order_items 引用了的行,默认情况为 NO ACTION,就是直接报错。

这个行为也可以手动指定:

CREATE TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
); CREATE TABLE orders (
order_id integer PRIMARY KEY,
shipping_address text,
...
); CREATE TABLE order_items (
product_no integer REFERENCES products ON DELETE RESTRICT, -- 限制,也就是禁止删除被它引用的行
order_id integer REFERENCES orders ON DELETE CASCADE, -- 级联,在删除被它引用的行的时候,这一行本身也会被自动删除掉
quantity integer,
PRIMARY KEY (product_no, order_id)
);

除了 RESTRICTCASCADE 外,在外键上的动作还有两个选项:SET NULLSET DEFAULT,顾名思义,就是在被引用的行删除后将外键设置为 NULL 或默认值。

ON UPDATEON DELETE 的动作是一样的,只是 CASCADE 表示同步更新。

3. CHECK 约束

CREATE TABLE products (
product_no integer,
name text,
price numeric CHECK (price > 0)
);

你还可以给这个约束取一个独立的名字。这样就可以令错误消息更清晰, 并且在你需要修改它的时候引用这个名字。语法是:

CREATE TABLE products (
product_no integer,
name text,
price numeric CONSTRAINT positive_price CHECK (price > 0)
);

稍微复杂一点的例子:

CREATE TABLE products (
product_no integer,
name text,
price numeric CHECK (price > 0),
discounted_price numeric,
CHECK (discounted_price > 0 AND price > discounted_price)
);

同样的,可以为 CHECK 命名,令错误信息更清晰:

CREATE TABLE products (
product_no integer,
name text,
price numeric,
CHECK (price > 0),
discounted_price numeric,
CHECK (discounted_price > 0),
CONSTRAINT valid_discount CHECK (price > discounted_price)
);

要注意的是,当约束表达式计算结果为真或 NULL 的时候,检查约束会被认为是满足条件的。 因为大多数表达式在含有 NULL 操作数的时候结果都是 NULL ,所以这些约束不能阻止字段值为 NULL 。要排除掉 NULL,只能使用 NOT NULL 约束。(所以就说 NULL 是万恶之源hhh)

参考

SQL 基础笔记(三):约束的更多相关文章

  1. SQL 基础笔记(一)

    本笔记整理自<SQL 基础教程>.<MySQL 必知必会>和网上资料.个人笔记不保证正确. 一.基础 SQL,即结构化查询语言,是为访问与操作关系数据库中的数据而设计的语言. ...

  2. SQL 基础笔记(二):进阶查询

    本笔记整理自<SQL 基础教程>.<MySQL 必知必会>和网上资料.个人笔记不保证正确. 一.复杂查询 视图 将 SELECT 查询包装成一个虚拟表,该虚拟表就被称为视图.( ...

  3. MYSQL基础笔记(三)-表操作基础

    数据表的操作 表与字段是密不可分的. 新增数据表 Create table [if not exists] 表名( 字段名 数据类型, 字段名 数据类型, 字段n 数据类型 --最后一行不需要加逗号 ...

  4. SQL基础笔记

    Codecademy中Learn SQL, SQL: Table Transformaton和SQL: Analyzing Business Metrics三门课程的笔记,以及补充的附加笔记. Cod ...

  5. SQL学习笔记三(补充-3)之MySQL完整性约束

    阅读目录 一 介绍 二 not null与default 三 unique 四 primary key 五 auto_increment 六 foreign key 七 作业 一 介绍 约束条件与数据 ...

  6. SQL学习笔记三(补充-2)之MySQL数据类型

    阅读目录 一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型 一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 ...

  7. 8、SQL基础整理(约束)

    约束 主键约束 防止在新增数据时出错,有约束性,起唯一标志的作用,在新增条目的时候防止不慎添加重复内容(不允许有null值) 1.  右键—设计—设置主键 2.在创建表格时设置 code int pr ...

  8. sql基础笔记备忘

    MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 数值类型:tinyint smallint medium ...

  9. SQL基础(三):SQL命令

    下面2个表用于实例演示: 1.SQL UNION 操作符 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的每个 SELECT 语句必须拥有相同数量的列.列 ...

随机推荐

  1. 兼容性良好的 sticky-footer 布局

    <div class="content"> <div class="content-wrapper"> <div class=&q ...

  2. nginx 方向代理

    #nginx 监听原理 先监听端口 --> 再配置域名 -->匹配到就访问local 否则 没有匹配到域名就默认访问第一个监听端口的local地址 # vi nginx.conf user ...

  3. 带你解析Java类加载机制

      目录 Java类加载机制的七个阶段 加载 验证 准备(重点) 解析 初始化(重点) 使用 卸载 实战分析 方法论 树义有话说 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如 ...

  4. MVVM、MVC框架的认识

    推荐博客: https://blog.csdn.net/jia12216/article/details/55520426 https://www.cnblogs.com/sunny_z/p/7093 ...

  5. 记录JavaScript的util.js类库

    工作中用到的, 不断做为积累, 以后能用到. 也感谢前辈们.  定义Util对象 var MyUtil = new Object(); 从url中获取参数 //从url中获取参数 function G ...

  6. MySQL——用户与密码

    mysql安装完成之后,在/var/log/mysqld.log文件中给root生成了一个默认密码.通过下面的方式找到root默认密码,然后登录mysql进行修改: grep 'temporary p ...

  7. Mybatis中多个参数的问题&&动态SQL&&查询结果与类的对应

    ### 1. 抽象方法中多个参数的问题 在使用MyBatis时,接口中的抽象方法只允许有1个参数,如果有多个参数,例如: Integer updatePassword( Integer id, Str ...

  8. SpringBoot配置redis和分布式session-redis

    springboot项目 和传统项目 配置redis的区别,更加简单方便,在分布式系统中,解决sesssion共享问题,可以用spring session redis. 1.pom.xml <d ...

  9. LVS-DR模式实现调度负载

    本篇文章主要梳理一下LVS前端调度过程及用户请求过程 实验架构 准备工作 添加各主机路由联通主机通信 Client IP route add default gw 172.20.17.19 Route ...

  10. Linux分享笔记:shell终端的介绍

    [1] Linux中 “shell终端” 和 “bash解释器” 的区别 shell终端是通过基于系统调用接口开发出的程序,用来让用户与系统进行对话,管理计Linux系统.它是一个命令行工具,操作类似 ...