SQL 基础笔记(三):约束
个人笔记不保证正确。
数据类型是限制我们可以在表里存储什么数据的一种方法。不过,对于许多应用来说, 这种限制实在是太粗糙了。比如,一个包含产品价格的字段应该只接受正数。 但是没有哪种标准数据类型只接受正数。 另外一个问题是你可能需要根据其它字段或者其它行的数据来约束字段数据。比如, 在一个包含产品信息的表中,每个产品编号都应该只有一行。
对于这些问题,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 DELETE 与 ON 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)
);
除了 RESTRICT 和 CASCADE 外,在外键上的动作还有两个选项:SET NULL 和 SET DEFAULT,顾名思义,就是在被引用的行删除后将外键设置为 NULL 或默认值。
ON UPDATE 与 ON 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 基础笔记(三):约束的更多相关文章
- SQL 基础笔记(一)
本笔记整理自<SQL 基础教程>.<MySQL 必知必会>和网上资料.个人笔记不保证正确. 一.基础 SQL,即结构化查询语言,是为访问与操作关系数据库中的数据而设计的语言. ...
- SQL 基础笔记(二):进阶查询
本笔记整理自<SQL 基础教程>.<MySQL 必知必会>和网上资料.个人笔记不保证正确. 一.复杂查询 视图 将 SELECT 查询包装成一个虚拟表,该虚拟表就被称为视图.( ...
- MYSQL基础笔记(三)-表操作基础
数据表的操作 表与字段是密不可分的. 新增数据表 Create table [if not exists] 表名( 字段名 数据类型, 字段名 数据类型, 字段n 数据类型 --最后一行不需要加逗号 ...
- SQL基础笔记
Codecademy中Learn SQL, SQL: Table Transformaton和SQL: Analyzing Business Metrics三门课程的笔记,以及补充的附加笔记. Cod ...
- SQL学习笔记三(补充-3)之MySQL完整性约束
阅读目录 一 介绍 二 not null与default 三 unique 四 primary key 五 auto_increment 六 foreign key 七 作业 一 介绍 约束条件与数据 ...
- SQL学习笔记三(补充-2)之MySQL数据类型
阅读目录 一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型 一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 ...
- 8、SQL基础整理(约束)
约束 主键约束 防止在新增数据时出错,有约束性,起唯一标志的作用,在新增条目的时候防止不慎添加重复内容(不允许有null值) 1. 右键—设计—设置主键 2.在创建表格时设置 code int pr ...
- sql基础笔记备忘
MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 数值类型:tinyint smallint medium ...
- SQL基础(三):SQL命令
下面2个表用于实例演示: 1.SQL UNION 操作符 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的每个 SELECT 语句必须拥有相同数量的列.列 ...
随机推荐
- spring入门(八) spring mvc设置默认首页
1.web.xml配置如下 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3// ...
- select()事件默认选中文本框的全部内容,并改变其背景色和文字颜色
1.select()事件默认选中文本框的全部内容 拿到input标签的节点,调用select()方法即可.但是我做的vue项目中调用了此方法有一个bug,单次点击会全选内容,双次点击的时候全选会闪一下 ...
- 『ACM C++』Virtual Judge | 两道基础题 - The Architect Omar && Malek and Summer Semester
这几天一直在宿舍跑PY模型,学校的ACM寒假集训我也没去成,来学校的时候已经18号了,突然加进去也就上一天然后排位赛了,没学什么就去打怕是要被虐成渣,今天开学前一天,看到最后有一场大的排位赛,就上去试 ...
- 【解决】docker 容器中 consul集群问题处理
现象描述: node1 和node2 日志反复出现 add remove node3节点. node3 节点 一直 驳回 node1 和node2 认为node3已经dead的消息 不断重启se ...
- PHP学习day1
PHP 变量规则: 变量以 $ 符号开头,其后是变量的名称 变量名称必须以字母或下划线开头 变量名称不能以数字开头 变量名称只能包含字母数字字符和下划线(A-z.0-9 以及 _) 变量名称对大小写敏 ...
- 部署node api的二三事
当接到node开发node api的时候,我就想用docker来部署,众所周知,node的版本更新迭代很快.很多以前需要babel后才能采用的方法正在不断被node 原生的支持.如果随便更换生产服务器 ...
- [转]Nginx伪静态配置和常用Rewrite伪静态规则集锦
Nginx伪静态配置和常用Rewrite伪静态规则集锦 作者: 字体:[增加 减小] 类型:转载 时间:2014-06-10 我要评论 伪静态是一种可以把文件后缀改成任何可能的一种方法,如果我想把ph ...
- 微信小程序关于tabbar点击切换数据不刷新问题
微信小程序中经常遇到的需求就是我提交了一个表单或者进行了一个操作,需要在我的个人中心页面中实时显示出来,但是小程序中的tabbar切换类似于tab切换 并不会进行页面刷新请求 所以总是会造成一些数据更 ...
- MyBatis实现拦截器分页功能
1.原理 在mybatis使用拦截器(interceptor),截获所执行方法的sql语句与参数. (1)修改sql的查询结果:将原sql改为查询count(*) 也就是条数 (2)将语句sql进行拼 ...
- 常用数字信号的产生(C实现)-ARMA模型数据生成
ARMA模型属于信号现代谱估计的范畴,AR模型常用于信号的线性预测.AR模型最后归结为线性方程,MA最后为非线性方程,因此,AR模型使用较多. AR模型最后归结为解Yule-Walker方程,对应矩阵 ...