个人笔记不保证正确。

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

对于这些问题,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. Code First 一

    Code-First和我们的数据库优先方式是相反的,数据库优先是通过数据库映射出相应的类和上下文,Code-First测试通过创建的类和上下文得到相应的数据库. Code-First主要用于领域驱动设 ...

  2. UDP端口启动后一段时间无法接收到数据

    接口需求:开发一个UDP协议的接口作为服务端接收来自客户端的认证数据,数据量每分钟7w+条; 数据格式:标准的redius协议,redius协议的相关知识在网上查资料,提供线索:http://blog ...

  3. zepto 基础知识(4)

    61.prev prev() 类型:collection prev(selector) 类型:collection 获取对相集合中每一个元素的钱一个兄弟节点,通过选择器来进行过滤 62.prev pr ...

  4. CF练习记录

    2018/5/6 Codeforces Round #478 (Div. 2) C http://codeforces.com/contest/975/problem/C Valhalla Siege ...

  5. (四)、python 集合与格式化

    一.set 集合 集合:可以包含多个元素,用逗号分割“,”   集合的作用:去重,关系运算, 1.不同元素组成2.无序3.集合中元素必须是不可变类型(可hash,可作为字典的key) 使用方法: 1) ...

  6. android发布帖子类技术

    最近练习一些关于发布帖子的技术,说来也简单,就学了一点皮毛吧!好了,下面就上代码吧! 首先设计服务器的访问类,大家都知道现在东西都要联网的嘛! JSONParser的类: public class J ...

  7. react native 踩坑之 SectionList state更新 不执行render重新渲染页面

    官方文档中指出 SectionList 本组件继承自PureComponent而非通常的Component,这意味着如果其props在浅比较中是相等的,则不会重新渲染.所以请先检查你的renderIt ...

  8. Linux 内核之api_man 手册安装

    开发环境:Ubuntu18.04,虚拟机virtual box 1.安装XML格式转换 sudo apt  install xmlto 2.在内核目录执行 make mandocs  大概持续了半小时 ...

  9. mysql5.7数据库与5.7之前版本比较

    数据库初始化方式变更 <5.7 版本 mysql_install_db >5.7 版本 bin/mysqld --initialize --user =mysql --basedir=/u ...

  10. [【转】ubuntu 16.10 Server 安装及基本部署

    一.Ubuntu Server 16.10 LTS 系统安装 Ubuntu 16.10 分为 桌面版 (desktop)和服务器版(Server).两者对于用户而言,最大的区别在于桌面版有图形操作界面 ...