sql必知会读书笔记

sql必知会读书笔记

  1. sql是什么

    SQL (发音为字母 S-Q-L 或 sequel )是结构化查询语言( Structured Query Language )的缩写。 SQL 是一种专门用来与数据库沟通的语言。

  2. 为什么

    设计 SQL 的目的是很好地完成一项任务 —— 提供一种从数据库中读写数据的简单有效的方法。

    标准 SQL 由 ANSI 标准委员会管理,从而称为 ANSI SQL 。

1. 数据库基础

概念:

  1. 数据库(database)
    保存有组织的数据的容器
  2. 表(table)
    表是一种结构化的文件,可用来存储某种特定类型的数据。
  3. 模式(schema)
    关于数据库和表的布局及特性的信息。这些特性定义了数据在表中如何存储,包含存储什么样的数据,数据如何分解,各部分信息如何命名等信息。
  4. 列( column )
    表中的一个字段。所有表都是由一个或多个列组成的。
  5. 数据类型
    所允许的数据的类型。每个表列都有相应的数据类型,它限制(或允许)该列中存储的数据。

注意:数据类型兼容
数据类型及其名称是 SQL 不兼容的一个主要原因。虽然大多数基本数据类型得到了一致的支持,但许多高级的数据类型却没有。更糟的是,
偶然会有相同的数据类型在不同的 DBMS 中具有不同的名称。

  1. 行(row)

    表中的一个记录。表中的数据是按行存储的,所保存的每个记录存储在自己的行内。

  2. 主键( primary key )
    一列(或一组列),其值能够唯一标识表中每一行。

    主键的条件:

    1. 任意两行都不具有相同的主键值;
    2. 每一行都必须具有一个主键值(主键列不允许NULL值);
    3. 主键列中的值不允许修改或更新;
    4. 主键值不能重用(如果某行从表中删除,它的主键不能赋给以后的新行)。

2. 检索数据

提示:

  1. 结束 SQL 语句。多条 SQL 语句必须以分号(;)分隔。多数 DBMS 不需要在单条 SQL 语句后加分号。

  2. SQL 语句不区分大小写,因此SELECT与select是相同的。

  3. 使用空格。在处理 SQL 语句时,其中所有空格都被忽略。

  4. 当心逗号。在选择多个列时,一定要在列名之间加上逗号,但最后一个列名后不加。如果在最后一个列名后加了逗号,将出现错误

注释:

单行:“#” 开头

多行:/* */

3. 排序检索数据

ORDER BY 子句的位置
在指定一条ORDER BY子句时,应该保证它是SELECT语句中最后一条子句。如果它不是最后的子句,将会出现错误消息

按多个列排序

下面的代码检索 3 个列,并按其中两个列对结果进行排序 —— 首先按价格,然后按名称排序。

1
2
3
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price, prod_name;

按列位置排序

1
2
3
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY 2, 3;

ORDER BY 2,3表示先按prod_price,再按prod_name进行排序。

指定排序方向

DESC

DESC关键字只应用到直接位于其前面的列名。

警告:在多个列上降序排序
如果想在多个列上进行降序排序,必须对每一列指定DESC关键字。

4. 过滤数据

WHERE 子句

在SELECT语句中,数据根据WHERE子句中指定的搜索条件进行过滤。WHERE子句在表名(FROM子句)之后给出,

警告: WHERE 子句的位置
在同时使用ORDER BY和WHERE子句时,应该让ORDER BY位于WHERE之后,否则将会产生错误

WHERE 子句操作符

操作符 说 明
BETWEEN 在指定的两个值之间
IS NULL 为 NULL 值
< > 不等于
1
2
3
4
SELECT prod_name, prod_price
FROM Products
WHERE (vend_id = 'DLL01' OR vend_id = ‘BRS01’)
AND prod_price >= 10;

这条SELECT语句与前一条的唯一差别是,将前两个条件用圆括号括了起来。因为圆括号具有比AND或OR操作符更高的求值顺序,所以 DBMS 首先
过滤圆括号内的OR条件。这时, SQL 语句变成了选择由供应商DLL01或BRS01制造的且价格在 10 美元及以上的所有产品,这正是我们希望的结
果。

复杂查询

提示:在WHERE子句中使用圆括号
任何时候使用具有AND和OR操作符的WHERE子句,都应该使用圆括号明确地分组操作符。

IN操作符

为什么要使用IN操作符?其优点为:

在有很多合法选项时,IN操作符的语法更清楚,更直观。 在与其他AND和OR操作符组合使用IN时,求值顺序更容易管理。 IN操作符一般比一组OR操作符执行得更快(在上面这个合法选项很少的例子中,你看不出性能差异)。 IN的最大优点是可以包含其他SELECT语句,能够更动态地建立WHERE子句。

NOT操作符

5. 用通配符进行过滤

LIKE操作符

百分号(%)通配符

最常使用的通配符是百分号(%)。在搜索串中,%表示任何字符出现任意次数。

说明:区分大小写
根据DBMS的不同及其配置,搜索可以是区分大小写的。如果区分大小写,则’fish%’与Fish bean bag toy就不匹配。

警告:请注意NULL
通配符%看起来像是可以匹配任何东西,但有个例外,这就是NULL。子句WHERE prod_name LIKE ‘%’不会匹配产品名称为NULL的行。

下划线(_)通配符

另一个有用的通配符是下划线(_)。下划线的用途与%一样,但它只匹配单个字符,而不是多个字符。

说明:DB2通配符 DB2不支持通配符_。 _

_说明:Access通配符
如果使用的是Microsoft Access,需要使用?而不是_。

方括号([ ])通配符

方括号 ([]) 通配符用来指定一个字符集,它必须匹配指定位置(通配符的位置)的一个字符。

使用通配符的技巧

  • 不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符。

  • 在确实需要使用通配符时,也尽量不要把它们用在搜索模式的开始处。把通配符置于开始处,搜索起来是最慢的。

  • 仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。

7.计算字段

CustomersCustomers

拼接字段

执行算数计算

加减乘除(+ - * /)

8. 使用数据处理函数

DBMS 函数的差异

函  数 语  法
提取字符串的组成部分 Access 使用 MID() ; DB2 、 Oracle 、 PostgreSQL 和 SQLite 使用 SUBSTR() ; MySQL 和 SQL Server 使用 SUBSTRING()
数据类型转换 Access 和 Oracle 使用多个函数,每种类型的转换有一个函数; DB2 和 PostgreSQL 使用 CAST() ; MariaDB 、 MySQL 和 SQL Server 使用
CONVERT()
取当前日期 Access 使用 NOW() ; DB2 和 PostgreSQL 使用 CURRENT_DATE ; MariaDB 和 MySQL 使用 CURDATE() ; Oracle 使用 SYSDATE ; SQL Server
使用 GETDATE() ; SQLite 使用 DATE()

常用的文本处理函数

函  数 说  明
LEFT() (或使用子字符串函数) 返回字符串左边的字符
LENGTH() (也使用 DATALENGTH() 或 LEN() ) 返回字符串的长度
LOWER() ( Access 使用 LCASE() ) 将字符串转换为小写
LTRIM() 去掉字符串左边的空格
RIGHT() (或使用子字符串函数) 返回字符串右边的字符
RTRIM() 去掉字符串右边的空格
SOUNDEX() 返回字符串的 SOUNDEX 值
UPPER() ( Access 使用 UCASE() ) 将字符串转换为大写

数值处理函数

函  数 说  明
ABS() 返回一个数的绝对值
COS() 返回一个角度的余弦
EXP() 返回一个数的指数值
PI() 返回圆周率
SIN() 返回一个角度的正弦
SQRT() 返回一个数的平方根
TAN() 返回一个角度的正切

9. 聚集函数

SQL 聚集函数

函  数 说  明
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回指定列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和

AVG()

警告:只用于单个列

AVG()只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出。为了获得多个列的平均值,必须使用多个AVG()函数。

AVG()函数忽略列值为NULL的行。

count

使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。

使用COUNT(column)对特定列中具有值的行进行计数,忽略NULL值。

MAX()函数

提示:对非数值数据使用MAX()

虽然MAX()一般用来找出最大的数值或日期值,但许多(并非所有)DBMS允许将它用来返回任意列中的最大值,包括返回文本列中的最大 值。在用于文本数据时,MAX()返回按该列排序后的最后一行。

说明:NULL值

MAX()函数忽略列值为NULL的行。

MIN()函数

SUM()函数

SUM()用来返回指定列值的和(总计)。

10. 分组数据

在使用GROUP BY子句前,需要知道一些重要的规定。

  • GROUP BY子句可以包含任意数目的列,因而可以对分组进行嵌套,更细致地进行数据分组。

  • 如果在GROUP BY子句中嵌套了分组,数据将在最后指定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。

  • GROUP BY子句中列出的每一列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。

  • 大多数SQL实现不允许GROUP BY列带有长度可变的数据类型(如文本或备注型字段)。

  • 除聚集计算语句外,SELECT语句中的每一列都必须在GROUP BY子句中给出。

  • 如果分组列中包含具有NULL值的行,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。

  • GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。

过滤分组

HAVING和WHERE的差别

WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要的区别,WHERE排除的行不包括在分组 中。这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。

使用HAVING时应该结合GROUP BY子句,而WHERE子句用于标准的行级过滤。

分组和排序

18. 视图

视图为虚拟的表。它们包含的不是数据而是根据需要检索数据的查询。视图提供了一种封装SELECT语句的层次,可用来简化数据处理,重新格 式化或保护基础数据。

是什么

视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。

为什么

  1. 重用SQL语句。

  2. 简化复杂的SQL操作。在编写查询后,可以方便地重用它而不必知道其基本查询细节。

  3. 使用表的一部分而不是整个表。

  4. 保护数据。可以授予用户访问表的特定部分的权限,而不是整个表的访问权限。

  5. 更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。

警告:性能问题

因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时需要的所有检索。如果你用多个联结和过滤创建了复杂的视图或者嵌套 了视图,性能可能会下降得很厉害。因此,在部署使用了大量视图的应用前,应该进行测试。

视图的规则和限制

  • 与表一样,视图必须唯一命名(不能给视图取与别的视图或表相同的名字)。

  • 对于可以创建的视图数目没有限制。

  • 创建视图,必须具有足够的访问权限。这些权限通常由数据库管理人员授予。

  • 视图可以嵌套,即可以利用从其他视图中检索数据的查询来构造视图。所允许的嵌套层数在不同的DBMS中有所不同(嵌套视图可能会严

  • 重降低查询的性能,因此在产品环境中使用之前,应该对其进行全面测试)。

  • 许多DBMS禁止在视图查询中使用ORDER BY子句。

  • 有些DBMS要求对返回的所有列进行命名,如果列是计算字段,则需要使用别名(关于列别名的更多信息,请参阅第7课)。

  • 视图不能索引,也不能有关联的触发器或默认值。

  • 有些DBMS把视图作为只读的查询,这表示可以从视图检索数据,但不能将数据写回底层表。详情请参阅具体的DBMS文档。

  • 有些DBMS允许创建这样的视图,它不能进行导致行不再属于视图的插入或更新。例如有一个视图,只检索带有电子邮件地址的顾客。如

  • 果更新某个顾客,删除他的电子邮件地址,将使该顾客不再属于视图。这是默认行为,而且是允许的,但有的DBMS可能会防止这种情况 发生。

视图的使用

创建和删除

视图用CREATE VIEW语句来创建

删除视图,可以使用DROP语句,其语法为DROP VIEW viewname。覆盖(或更新)视图,必须先删除它,然后再重新创建。

作用

  1. 利用视图简化复杂的联结

  2. 用视图重新格式化检索出的数据

  3. 用视图过滤不想要的数据

  4. 使用视图与计算字段

19. 存储过程

可以创建存储过程。简单来说,存储过程就是为以后使用而保存的一条或多条SQL语句。可将其视为批文件,虽然它们的作用不仅限于批处理。

是什么

为什么

  • 通过把处理封装在一个易用的单元中,可以简化复杂的操作(如前面例子所述)。

  • 由于不要求反复建立一系列处理步骤,因而保证了数据的一致性。如果所有开发人员和应用程序都使用同一存储过程,则所使用的代码都是相同的。

  • 这一点的延伸就是防止错误。需要执行的步骤越多,出错的可能性就越大。防止错误保证了数据的一致性。

  • 简化对变动的管理。如果表名、列名或业务逻辑(或别的内容)有变化,那么只需要更改存储过程的代码。使用它的人员甚至不需要知道 这些变化。

  • 这一点的延伸就是安全性。通过存储过程限制对基础数据的访问,减少了数据讹误(无意识的或别的原因所导致的数据讹误)的机会。 因为存储过程通常以编译过的形式存储,所以DBMS处理命令的工作较少,提高了性能。

  • 存在一些只能用在单个请求中的SQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。

换句话说,使用存储过程有三个主要的好处,即简单、安全、高性能。显然,它们都很重要。不过,在将SQL代码转换为存储过程前,也必须

知道它的一些缺陷。

  • 不同DBMS中的存储过程语法有所不同。事实上,编写真正的可移植存储过程几乎是不可能的。不过,存储过程的自我调用(名字以及数 据如何传递)可以相对保持可移植。因此,如果需要移植到别的DBMS,至少客户端应用代码不需要变动。

  • 一般来说,编写存储过程比编写基本SQL语句复杂,需要更高的技能,更丰富的经验。因此,许多数据库管理员把限制存储过程的创建作

为安全措施(主要受上一条缺陷的影响)。

创建

1
2
3
4
5
create procedure productpricing()
BEGIN
SELECT AVG(prod_price) AS priceaverage
FROM products;
END

用CREATE PROCEDURE productpricing()语句定义。如果存储过程接受参数,它们将在()中列举出来。存储过程的代码位于BEGIN和END语句内,

mysql命令行客户机的分隔符

DELIMITER //告诉命令行实用程序使用//作为新的语句结束分隔符,

使用

1
CALL productpricing()

删除

1
2
DROP PROCEDURE productpricing;
DROP PROCEDURE productpricing IF EXISTS;

使用参数

1
2
3
4
5
6
7
8
9
10
create procedure productpricing(
OUT p1 DECIMAL(8, 2),
OUT ph DECIMAL(8, 2),
OUT pa DECIMAL(8, 2)
)
BEGIN
SELECT MIN(prod_price) INTO p1 FROM products;
SELECT MAX(prod_price) INTO ph FROM products;
SELECT AVG(prod_price) INTO pa FROM products
END;

每个参数必须具有指定的类型,这里使用十进制值(DECIMAL 关键字)。关键字OUT指出相应的参数用来从存储过程传出一个值(返回给调用者)。MySQL支持IN(传递给存储过程)、OUT(从存储过程传出,如这里所用)和INOUT(对存储过程传入和传出)类型的参数。

使用

1
2
CALL productpricing(@procelow, @pricehigh, @priceAverage);
SELECT @procelow;

变量名: 所有MySQL变量都必须以@开始。

建立智能存储过程

只有在存储过程内包含业务规则和智能处理时,它们的威力才真正显现出来。

用DECLARE语句定义了两个局部变量。DECLARE要求指定变量名和数据类型,它也支持可选的默认值.

COMMENT关键字 本例子中的存储过程在CREATE PROCEDURE语
句中包含了一个COMMENT值。它不是必需的,但如果给出,将
在SHOW PROCEDURE STATUS的结果中显示。

检查存储过程

1
2
3
4
# 显示用来创建一个存储过程的CREATE语句
SHOW CREATE PROCEDURE ordertotal;
# 了获得包括何时、由谁创建等详细信息的存储过程列表
SHOW STATUS PROCEDURE ordertotal;

20. 管理事务处理

为什么

使用事务处理(transaction processing),通过确保成批的SQL操作要么完全执行,要么完全不执行,来维护数据库的完整

  • 事务(transaction)指一组SQL语句;
  • 回退(rollback)指撤销指定SQL语句的过程;
  • 提交(commit)指将未存储的SQL语句结果写入数据库表;
  • 保留点(savepoint)指事务处理中设置的临时占位符(placeholder),可以对它发布回退(与回退整个事务处理不同)

控制事务处理

管理事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。

1
2
3
4
5
6
7
8
9
10
11
12
# 开始事务
start transaction

# 回退
ROLLBACK

# 提交
COMMIT

# 保留点, 部分回退
SAVEPOINT point1;
ROLLBACK TO point1

ROLLBACK命令用来回退(撤销)MySQL语句

ROLLBACK** 只能在一个事务处理内使用(在执行一条STARTTRANSACTION命令之后)。

一般的MySQL语句都是直接针对数据库表执行和编写的。这就是所谓的隐含提交(implicit commit),即提交(写或保存)操作是自动进行的。

​ 但是,在事务处理块中,提交不会隐含地进行。为进行明确的提交,使用COMMIT语句.

隐含事务关闭 :当COMMIT或ROLLBACK语句执行后,事务会自动关闭(将来的更改会隐含提交)

保留点越多越好可以在SQL代码中设置任意多的保留点,越多越好。为什么呢?因为保留点越多,你就越能灵活地进行回退。

21. 使用游标

结果集(result set)SQL查询所检索出的结果。

为什么

有时,需要在检索出来的行中前进或后退一行或多行,这就是游标的用途所在。

是什么

游标(cursor)是一个存储在DBMS服务器上的数据库查询, 它不是一条SELECT语句,而是被该语句检索出来的结果集。

选项和特性

  • 能够标记游标为只读,使数据能读取,但不能更新和删除。

  • 能控制可以执行的定向操作(向前、向后、第一、最后、绝对位置、相对位置等)。

  • 能标记某些列为可编辑的,某些列为不可编辑的。

  • 规定范围,使游标对创建它的特定请求(如存储过程)或对所有请求可访问。

  • 指示DBMS对检索出的数据(而不是指出表中活动数据)进行复制,使数据在游标打开和访问期间不变化。

说明:游标与基于Web的应用

使用游标

步骤:

  1. 在使用游标前,必须声明(定义)它。这个过程实际上没有检索数据,它只是定义要使用的SELECT语句和游标选项。

  2. 一旦声明,就必须打开游标以供使用。这个过程用前面定义的SELECT语句把数据实际检索出来。

  3. 对于填有数据的游标,根据需要取出(检索)各行。

  4. 在结束游标使用时,必须关闭游标,可能的话,释放游标(有赖于具体的DBMS)。

使用DECLARE语句创建游标

创建

使用

22. 高级SQL特性

约束

是什么

约束(constraint) 管理如何插入或处理数据库数据的规则。

包括:主键、外键、唯一约束、检查约束

主键

满足条件:

  • 任意两行的主键值都不相同。

  • 每行都具有一个主键值(即列中不允许NULL值)。

  • 包含主键值的列从不修改或更新。(大多数DBMS不允许这么做,但如果你使用的DBMS允许这样做,好吧,千万别!)

  • 主键值不能重用。如果从表中删除某一行,其主键值不分配给新行。

指定列为主键: PRIMARY KEY

外键

外键是表中的一列,其值必须列在另一表的主键中。外键是保证引用完整性的极其重要部分。

外键有助防止意外删除

唯一约束

主键和唯一约束区别:

  • 表可包含多个唯一约束,但每个表只允许一个主唯一约束列可包含NULL值。
  • 唯一约束列可修改或更新。
  • 唯一约束列的值可重复使用。与
  • 主键不一样,唯一约束不能用来定义外键。

检查约束

检查约束用来保证一列(或一组列)中的数据满足一组指定的条件。检查约束的常见用途有以下几点。

  • 检查最小或最大值。例如,防止0个物品的订单(即使0是合法的数)。

  • 指定范围。例如,保证发货日期大于等于今天的日期,但不超过今天起一年后的日期。

  • 只允许特定的值。例如,在性别字段中只允许M或F。

索引

触发器

是什么:触发器是特殊的存储过程,它在特定的数据库活动发生时自动执行。

一般来说,约束的处理比触发器快,因此在可能的时候,应该尽量使用约束。

数据库安全

  • 对数据库管理功能(创建表、更改或删除已存在的表等)的访问;

  • 对特定数据库或表的访问;

  • 访问的类型(只读、对特定列的访问等);

  • 仅通过视图或存储过程对表进行访问;

  • 创建多层次的安全措施,从而允许多种基于登录的访问和控制;

  • 限制管理用户账号的能力。

关键字

关键字 作用 附加说明
SELECT 要返回的列或表达式
FROM 从中检索数据的表
WHERE 指定搜索条件进行过滤(行级过滤) 范围值检查:BETWEEN xx AND xx
指定条件范围:IN(xx, xx)
否定其后条件:NOT
GROUP BY 分组 组级过滤:HAVING
ORDER BY 输出排序顺序 降序:DESC (DESCENDING)
升序(默认):ASC(ASCENDING)
DISTINCT distinct
IS NULL 非空检查
AND 、OR 逻辑操作符
LIKE
  1. distinct

    它指示数据库只返回不同的值。

    eg:SELECT DISTINCT vend_id FROM Products;

    警告:不能部分使用 DISTINCT
    DISTINCT关键字作用于所有的列,不仅仅是跟在其后的那一列。例如,你指定SELECT DISTINCT vend_id, prod_price,除非指定的两列完
    全相同,否则所有的行都会被检索出来。