SQL 必知必会 - 数据更新/存储/事务
SQL 必知必会 - 全书目录
- 第 01 - 10 章:SQL 必知必会 - 单表查询/过滤/汇总
- 第 11 - 24 章:SQL 必知必会 - 多表查询/联结/组合
- 第 15 - 24 章:SQL 必知必会 - 数据更新/存储/事务
插入数据 - INSERT
INSERT
用来将行插入(或添加)到数据库表- 在某些 SQL 实现中,跟在
INSERT
之后的INTO
关键字是可选的
- 在某些 SQL 实现中,跟在
- 插入完整的行
- 不要使用没有明确给出列的
INSERT
语句 VALUES
的数目都必须正确
- 不要使用没有明确给出列的
- 插入行的一部分
- 可以在
INSERT
操作中省略某些列- 该列定义为允许
NULL
值(无值或空值) - 在表定义中给出默认值。这表示如果不给出值,将使用默认值
- 该列定义为允许
- 可以在
- 插入某些查询的结果:
INSERT SELECT
INSERT SELECT
中SELECT
语句可以包含WHERE
子句,以过滤插入的数据
INSERT
通常只插入一行。要插入多行,必须执行多个INSERT
语句。INSERT SELECT
是个例外,它可以用一条INSERT
插入多行,不管SELECT
语句返回多少行,都将被INSERT
插入
1 | -- 插入完整的行, 必须给每一列提供一个值 |
- 从一个表复制到另一个表:使用
SELECT INTO
语句- 任何
SELECT
选项和子句都可以使用,包括WHERE
和GROUP BY
- 可利用联结从多个表插入数据
- 不管从多少个表中检索数据,数据都只能插入到一个表中
- 任何
1 | -- 创建一个名为 CustCopy 的新表, 并把 Customers 表的整个内容复制到新表中 |
更新和删除数据 - UPDATE/DELETE
更新数据
- 更新数据:
UPDATE
语句,不要省略WHERE
子句,否则将会更新所有行 - 基本的
UPDATE
语句- 要更新的表
- 列名和它们的新值
- 确定要更新哪些行的过滤条件
UPDATE
语句中可以使用子查询,使得能用SELECT
语句检索出的数据更新列数据- 要删除某个列的值,可设置它为
NULL
(假如表定义允许NULL
值)
1 | UPDATE Customers |
删除数据
- 删除数据:
DELETE
语句,不要省略WHERE
子句,否则将会删除所有行 DELETE
不需要列名或通配符DELETE
删除整行而不是删除列DELETE
不删除表本身
1 | -- 从 Customers 表中删除一行 |
- 更新和删除的指导原则
- 除非确实打算更新和删除每一行,否则绝对不要使用不带
WHERE
子句的UPDATE
或DELETE
语句 - 保证每个表都有主键(如果忘记这个内容,请参阅第 12 课),尽可能像
WHERE
子句那样使用它(可以指定各主键、多个值或值的范围) - 在
UPDATE
或DELETE
语句使用WHERE
子句前,应该先用SELECT
进行测试,保证它过滤的是正确的记录,以防编写的WHERE 子句不正确。 - 使用强制实施引用完整性的数据库(关于这个内容,请参阅第 12 课),这样 DBMS 将不允许删除其数据与其他表相关联的行。
- 有的 DBMS 允许数据库管理员施加约束,防止执行不带
WHERE
子句的UPDATE
或DELETE
语句。如果所采用的 DBMS 支持这个特性,应该使用它。
- 除非确实打算更新和删除每一行,否则绝对不要使用不带
创建和操纵表 - CREATE/ALTER
创建表
- SQL 不仅用于表数据操纵,还用来执行数据库和表的所有操作,包括表本身的创建和处理。
- 用程序创建表,可以使用 SQL 的
CREATE TABLE
语句 - 在不同的 SQL 实现中,
CREATE TABLE
语句的语法可能有所不同 - 在创建新的表时,指定的表名必须不存在,否则会出错。
- 利用CREATE TABLE 创建表,必须给出下列信息:
- 新表的名字,在关键字CREATE TABLE 之后给出;
- 表列的名字和定义,用逗号分隔;
- 有的DBMS 还要求指定表的位置。
- 每个表列要么是
NULL
列,要么是NOT NULL
列,这种状态在创建时由表的定义规定。NULL
为默认设置 - SQL 允许指定默认值,在插入行时如果不给出值,DBMS 将自动采用默认值。
- 默认值在
CREATE TABLE
语句的列定义中用关键字DEFAULT
指定。 - 默认值经常用于日期或时间戳列。
- 通过指定引用系统日期的函数或变量, 将系统日期用作默认日期
1 | CREATE TABLE Products |
更新、删除表
- 更新表定义,可以使用
ALTER TABLE
语句。- 理想情况下,不要在表中包含数据时对其进行更新。应该在表的设计过程中充分考虑未来可能的需求,避免今后对表的结构做大改动。
- 所有的DBMS 都允许给现有的表增加列,不过对所增加列的数据类型(以及
NULL
和DEFAULT
的使用)有所限制。 - 许多DBMS 不允许删除或更改表中的列。
- 多数DBMS 允许重新命名表中的列。
- 许多DBMS 限制对已经填有数据的列进行更改,对未填有数据的列几乎没有限制。
- 使用
ALTER TABLE
更改表结构,必须给出下面的信息:- 在
ALTER TABLE
之后给出要更改的表名(该表必须存在,否则将
出错); - 列出要做哪些更改。
- 在
- 复杂的表结构更改一般需要手动删除过程,它涉及以下步骤:
1. 用新的列布局创建一个新表;
2. 使用INSERT SELECT
语句(关于这条语句的详细介绍,请参阅第 15
课)从旧表复制数据到新表。有必要的话,可以使用转换函数和计算字段;
3. 检验包含所需数据的新表;
4. 重命名旧表(如果确定,可以删除它);
5. 用旧表原来的名字重命名新表;
6. 根据需要,重新创建触发器、存储过程、索引和外键。 - 删除表:使用
DROP TABLE
语句 - 重命名表:
- DB2、MariaDB、MySQL、Oracle 和 PostgreSQL 用户使用
RENAME
语句 - SQL Server 用户使用
sp_rename
存储过程 - SQLite 用户使用
ALTER TABLE
语句
- DB2、MariaDB、MySQL、Oracle 和 PostgreSQL 用户使用
1 | -- 给 Vendors 表增加一个名为 vend_phone 的列 |
使用视图 - CREATE VIEW
- 视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。
- 视图的一些常见应用:
- 重用 SQL 语句,简化复杂的 SQL 操作
- 使用表的一部分而不是整个表
- 保护数据。可以授予用户访问表的特定部分的权限,而不是整个表的访问权限
- 更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据
- 视图创建和使用的一些最常见的规则和限制
- 与表一样,视图必须唯一命名
- 创建视图,必须具有足够的访问权限
- 视图可以嵌套,即可以利用从其他视图中检索数据的查询来构造视图。所允许的嵌套层数在不同的 DBMS 中有所不同
- 许多 DBMS 禁止在视图查询中使用
ORDER BY
子句 - 有些 DBMS 要求对返回的所有列进行命名,如果列是计算字段,则需要使用别名
- 视图不能索引,也不能有关联的触发器或默认值
- 有些 DBMS 把视图作为只读的查询,这表示可以从视图检索数据,但不能将数据写回底层表
- 有些 DBMS 允许创建这样的视图,它不能进行导致行不再属于视图的插入或更新
- 创建视图:
CREATE VIEW
语句 - 删除视图:可以使用
DROP
语句,其语法为DROP VIEW viewname
1 | -- 检索订购了某种产品的顾客 |
使用存储过程 - EXECUTE
- 存储过程就是为以后使用而保存的一条或多条 SQL 语句。可将其视为批文件,虽然它们的作用不仅限于批处理
- 为什么要使用存储过程:简单、安全、高性能
- 通过把处理封装在一个易用的单元中,可以简化复杂的操作
- 由于不要求反复建立一系列处理步骤,因而保证了数据的一致性
- 简化对变动的管理
- 因为存储过程通常以编译过的形式存储,所以 DBMS 处理命令所需的工作量少,提高了性能
- 存在一些只能用在单个请求中的 SQL 元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码
- 执行存储过程:
EXECUTE
- 创建存储过程:
CREATE
1 | EXECUTE AddNewProduct( 'JTS01', |
管理事务处理 - COMMIT/ROLLBACK
-
使用事务处理(transaction processing),通过确保成批的SQL 操作要么完全执行,要么完全不执行,来维护数据库的完整性
-
可以保证一组操作不会中途停止,它们要么完全执行,要么完全不执行(除非明确指示)
-
如果没有错误发生,整组语句提交给(写到)数据库表;如果发生错误,则进行回退(撤销),将数据库恢复到某个已知且安全的状态
-
关于事务处理需要知道的几个术语:
- 事务(transaction)指一组SQL 语句
- 回退(rollback)指撤销指定SQL 语句的过程
- 提交(commit)指将未存储的SQL 语句结果写入数据库表
- 保留点(savepoint)指事务处理中设置的临时占位符(placeholder),可以对它发布回退(与回退整个事务处理不同)。
-
事务处理用来管理
INSERT
、UPDATE
和DELETE
语句 -
管理事务的关键在于将SQL 语句组分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。
-
有的DBMS 要求明确标识事务处理块的开始和结束:
- SQL Server:
BEGIN TRANSACTION
COMMIT TRANSACTION
- SQL Server:
-
-
多数实现没有明确标识事
务处理在何处结束。事务一直存在,直到被中断- MariaDB 和 MySQL:
START TRANSACTION
- Oracle:
SET TRANSACTION
- PostgreSQL:
BEGIN
- PostgreSQL:
- 通常,
COMMIT
用于
保存更改,ROLLBACK
用于撤销
- MariaDB 和 MySQL:
-
要支持回退部分事务,必须在事务处理块中的合适位置放置占位符。在 SQL 中,这些占位符称为保留点
- MariaDB、MySQL 和 Oracle:
SAVEPOINT
- MariaDB、MySQL 和 Oracle:
1 | -- 执行 DELETE 操作,然后用 ROLLBACK 语句撤销 |
使用游标 - CURSOR
- 结果集(result set):SQL 查询所检索出的结果
- 游标(cursor)是一个存储在 DBMS 服务器上的数据库查询,它不是一条SELECT 语句,而是被该语句检索出来的结果集,应用程序可以根据需要滚动或浏览其中的数据
- 常见的一些选项和特性:
- 能够标记游标为只读,使数据能读取,但不能更新和删除
- 能控制可以执行的定向操作(向前、向后、第一、最后、绝对位置、相对位置等)
- 能标记某些列为可编辑的,某些列为不可编辑的
- 规定范围,使游标对创建它的特定请求(如存储过程)或对所有请求可访问
- 指示DBMS 对检索出的数据(而不是指出表中活动数据)进行复制,使数据在游标打开和访问期间不变化
- 游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改
- 创建游标:使用
DECLARE
语句创建游标,并定义相应的SELECT
语句,但不进行查询 - 使用游标:使用
OPEN CURSOR
语句打开游标,并执行查询 - 访问游标:使用
FETCH
语句访问游标数据,指出要检索哪些行,从何处检索它们以及将它们放于何处、 - 关闭游标:使用
CLOSE
语句关闭游标
1 | -- 创建游标, 找出空缺的电子邮件地址 |
高级SQL 特性
约束
- 管理如何插入或处理数据库数据的规则
- 主键:一种特殊的约束,用来保证一列(或一组列)中的值是唯一的,而且永不改动
- 主键值唯一且不为
NULL
,从不修改和更新,不能重用 - 定义主键的方法:
PRIMARY KEY
- 主键值唯一且不为
- 外键:是表中的一列,其值必须列在另一表的主键中
- 定义外键的方法:
REFERENCES
- 在定义外键后,DBMS 不允许删除在另一个表中具有关联行的行
- 级联删除:从一个表中删除行时删除所有相关的数据
- 定义外键的方法:
- 唯一约束:用来保证一列(或一组列)中的数据是唯一的
- 类似于主键,但存在以下重要区别:
- 表可包含多个唯一约束,但每个表只允许一个主键
- 唯一约束列可包含
NULL
值 - 唯一约束列可修改或更新
- 唯一约束列的值可重复使用
- 与主键不一样,唯一约束不能用来定义外键
- 使用
UNIQUE
关键字定义,也可以用单独的CONSTRAINT
定义
- 类似于主键,但存在以下重要区别:
- 检查约束:保证一列(或一组列)中的数据满足一组指定的条件
- 检查最小或最大值、指定范围、只允许特定的值
- 使用
CHECK
关键词定义
1 | -- 给表的 vend_id 列定义添加关键字 PRIMARY KEY,使其成为主键 |
索引
- 索引用来排序数据以加快搜索和排序操作的速度
- 主键数据总是排序的,按主键检索特定行总是一种快速有效的操作
- 搜索其他列中的值通常效率不高,解决方法是使用索引
- 可以在一个或多个列上定义索引,使 DBMS 保存其内容的一个排过序的列表
- 索引改善检索操作的性能,但降低了数据插入、修改和删除的性能
- 索引用
CREATE INDEX
语句创建,必须唯一命名 - 可能要占用大量的存储空间,并非所有数据都适合做索引
1 | CREATE INDEX prod_name_ind |
触发器
- 触发器(
TRIGGER
)是特殊的存储过程,它在特定的数据库活动发生时自动执行 - 触发器可以与特定表上的
INSERT
、UPDATE
和DELETE
操作相关联 - 触发器内的代码具有以下数据的访问权:
INSERT
操作中的所有新数据UPDATE
操作中的所有新数据和旧数据DELETE
操作中删除的数据
- 触发器的一些常见用途
- 保证数据一致
- 基于某个表的变动在其他表上执行活动
- 进行额外的验证并根据需要回退数据
- 计算计算列的值或更新时间戳
- 约束的处理比触发器快,因此在可能的时候,应该尽量使用约束
1 | -- 对所有 INSERT 和 UPDATE 操作 |
数据库安全
- 大多数 DBMS 都给管理员提供了管理机制,利用管理机制授予或限制对数据的访问
- 安全性使用 SQL 的
GRANT
和REVOKE
语句来管理
SQL 必知必会 - 全书目录
- 第 01 - 10 章:SQL 必知必会 - 单表查询/过滤/汇总
- 第 11 - 24 章:SQL 必知必会 - 多表查询/联结/组合
- 第 15 - 24 章:SQL 必知必会 - 数据更新/存储/事务
SQL 必知必会 - 数据更新/存储/事务