sql必知会读书笔记
sql是什么
SQL (发音为字母 S-Q-L 或 sequel )是结构化查询语言( Structured Query Language )的缩写。 SQL 是一种专门用来与数据库沟通的语言。
为什么
设计 SQL 的目的是很好地完成一项任务 —— 提供一种从数据库中读写数据的简单有效的方法。
标准 SQL 由 ANSI 标准委员会管理,从而称为 ANSI SQL 。
1. 数据库基础
概念:
- 数据库(database)
保存有组织的数据的容器 - 表(table)
表是一种结构化的文件,可用来存储某种特定类型的数据。 - 模式(schema)
关于数据库和表的布局及特性的信息。这些特性定义了数据在表中如何存储,包含存储什么样的数据,数据如何分解,各部分信息如何命名等信息。 - 列( column )
表中的一个字段。所有表都是由一个或多个列组成的。 - 数据类型
所允许的数据的类型。每个表列都有相应的数据类型,它限制(或允许)该列中存储的数据。
注意:数据类型兼容
数据类型及其名称是 SQL 不兼容的一个主要原因。虽然大多数基本数据类型得到了一致的支持,但许多高级的数据类型却没有。更糟的是,
偶然会有相同的数据类型在不同的 DBMS 中具有不同的名称。
行(row)
表中的一个记录。表中的数据是按行存储的,所保存的每个记录存储在自己的行内。
主键( primary key )
一列(或一组列),其值能够唯一标识表中每一行。主键的条件:
- 任意两行都不具有相同的主键值;
- 每一行都必须具有一个主键值(主键列不允许NULL值);
- 主键列中的值不允许修改或更新;
- 主键值不能重用(如果某行从表中删除,它的主键不能赋给以后的新行)。
2. 检索数据
提示:
结束 SQL 语句。多条 SQL 语句必须以分号(;)分隔。多数 DBMS 不需要在单条 SQL 语句后加分号。
SQL 语句不区分大小写,因此SELECT与select是相同的。
使用空格。在处理 SQL 语句时,其中所有空格都被忽略。
当心逗号。在选择多个列时,一定要在列名之间加上逗号,但最后一个列名后不加。如果在最后一个列名后加了逗号,将出现错误
注释:
单行:“#” 开头
多行:/* */
3. 排序检索数据
ORDER BY 子句的位置
在指定一条ORDER BY子句时,应该保证它是SELECT语句中最后一条子句。如果它不是最后的子句,将会出现错误消息
按多个列排序
下面的代码检索 3 个列,并按其中两个列对结果进行排序 —— 首先按价格,然后按名称排序。
1 | SELECT prod_id, prod_price, prod_name |
按列位置排序
1 | SELECT prod_id, prod_price, prod_name |
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 | SELECT prod_name, prod_price |
这条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语句的层次,可用来简化数据处理,重新格 式化或保护基础数据。
是什么
视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。
为什么
重用SQL语句。
简化复杂的SQL操作。在编写查询后,可以方便地重用它而不必知道其基本查询细节。
使用表的一部分而不是整个表。
保护数据。可以授予用户访问表的特定部分的权限,而不是整个表的访问权限。
更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。
警告:性能问题
因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时需要的所有检索。如果你用多个联结和过滤创建了复杂的视图或者嵌套 了视图,性能可能会下降得很厉害。因此,在部署使用了大量视图的应用前,应该进行测试。
视图的规则和限制
与表一样,视图必须唯一命名(不能给视图取与别的视图或表相同的名字)。
对于可以创建的视图数目没有限制。
创建视图,必须具有足够的访问权限。这些权限通常由数据库管理人员授予。
视图可以嵌套,即可以利用从其他视图中检索数据的查询来构造视图。所允许的嵌套层数在不同的DBMS中有所不同(嵌套视图可能会严
重降低查询的性能,因此在产品环境中使用之前,应该对其进行全面测试)。
许多DBMS禁止在视图查询中使用ORDER BY子句。
有些DBMS要求对返回的所有列进行命名,如果列是计算字段,则需要使用别名(关于列别名的更多信息,请参阅第7课)。
视图不能索引,也不能有关联的触发器或默认值。
有些DBMS把视图作为只读的查询,这表示可以从视图检索数据,但不能将数据写回底层表。详情请参阅具体的DBMS文档。
有些DBMS允许创建这样的视图,它不能进行导致行不再属于视图的插入或更新。例如有一个视图,只检索带有电子邮件地址的顾客。如
果更新某个顾客,删除他的电子邮件地址,将使该顾客不再属于视图。这是默认行为,而且是允许的,但有的DBMS可能会防止这种情况 发生。
视图的使用
创建和删除
视图用CREATE VIEW语句来创建
删除视图,可以使用DROP语句,其语法为DROP VIEW viewname。覆盖(或更新)视图,必须先删除它,然后再重新创建。
作用
利用视图简化复杂的联结
用视图重新格式化检索出的数据
用视图过滤不想要的数据
使用视图与计算字段
19. 存储过程
可以创建存储过程。简单来说,存储过程就是为以后使用而保存的一条或多条SQL语句。可将其视为批文件,虽然它们的作用不仅限于批处理。
是什么
为什么
通过把处理封装在一个易用的单元中,可以简化复杂的操作(如前面例子所述)。
由于不要求反复建立一系列处理步骤,因而保证了数据的一致性。如果所有开发人员和应用程序都使用同一存储过程,则所使用的代码都是相同的。
这一点的延伸就是防止错误。需要执行的步骤越多,出错的可能性就越大。防止错误保证了数据的一致性。
简化对变动的管理。如果表名、列名或业务逻辑(或别的内容)有变化,那么只需要更改存储过程的代码。使用它的人员甚至不需要知道 这些变化。
这一点的延伸就是安全性。通过存储过程限制对基础数据的访问,减少了数据讹误(无意识的或别的原因所导致的数据讹误)的机会。 因为存储过程通常以编译过的形式存储,所以DBMS处理命令的工作较少,提高了性能。
存在一些只能用在单个请求中的SQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。
换句话说,使用存储过程有三个主要的好处,即简单、安全、高性能。显然,它们都很重要。不过,在将SQL代码转换为存储过程前,也必须
知道它的一些缺陷。
不同DBMS中的存储过程语法有所不同。事实上,编写真正的可移植存储过程几乎是不可能的。不过,存储过程的自我调用(名字以及数 据如何传递)可以相对保持可移植。因此,如果需要移植到别的DBMS,至少客户端应用代码不需要变动。
一般来说,编写存储过程比编写基本SQL语句复杂,需要更高的技能,更丰富的经验。因此,许多数据库管理员把限制存储过程的创建作
为安全措施(主要受上一条缺陷的影响)。
创建
1 | create procedure productpricing() |
用CREATE PROCEDURE productpricing()语句定义。如果存储过程接受参数,它们将在()中列举出来。存储过程的代码位于BEGIN和END语句内,
mysql命令行客户机的分隔符
DELIMITER //告诉命令行实用程序使用//作为新的语句结束分隔符,
使用
1 | CALL productpricing() |
删除
1 | DROP PROCEDURE productpricing; |
使用参数
1 | create procedure productpricing( |
每个参数必须具有指定的类型,这里使用十进制值(DECIMAL 关键字)。关键字OUT指出相应的参数用来从存储过程传出一个值(返回给调用者)。MySQL支持IN(传递给存储过程)、OUT(从存储过程传出,如这里所用)和INOUT(对存储过程传入和传出)类型的参数。
使用
1 | CALL productpricing(@procelow, @pricehigh, @priceAverage); |
变量名: 所有MySQL变量都必须以@开始。
建立智能存储过程
只有在存储过程内包含业务规则和智能处理时,它们的威力才真正显现出来。
用DECLARE语句定义了两个局部变量。DECLARE要求指定变量名和数据类型,它也支持可选的默认值.
COMMENT关键字 本例子中的存储过程在CREATE PROCEDURE语
句中包含了一个COMMENT值。它不是必需的,但如果给出,将
在SHOW PROCEDURE STATUS的结果中显示。
检查存储过程
1 | # 显示用来创建一个存储过程的CREATE语句 |
20. 管理事务处理
为什么
使用事务处理(transaction processing),通过确保成批的SQL操作要么完全执行,要么完全不执行,来维护数据库的完整
- 事务(transaction)指一组SQL语句;
- 回退(rollback)指撤销指定SQL语句的过程;
- 提交(commit)指将未存储的SQL语句结果写入数据库表;
- 保留点(savepoint)指事务处理中设置的临时占位符(placeholder),可以对它发布回退(与回退整个事务处理不同)
控制事务处理
管理事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。
1 | # 开始事务 |
ROLLBACK命令用来回退(撤销)MySQL语句
ROLLBACK** 只能在一个事务处理内使用(在执行一条STARTTRANSACTION命令之后)。
一般的MySQL语句都是直接针对数据库表执行和编写的。这就是所谓的隐含提交(implicit commit),即提交(写或保存)操作是自动进行的。
但是,在事务处理块中,提交不会隐含地进行。为进行明确的提交,使用COMMIT语句.
隐含事务关闭 :当COMMIT或ROLLBACK语句执行后,事务会自动关闭(将来的更改会隐含提交)
保留点越多越好可以在SQL代码中设置任意多的保留点,越多越好。为什么呢?因为保留点越多,你就越能灵活地进行回退。
21. 使用游标
结果集(result set)SQL查询所检索出的结果。
为什么
有时,需要在检索出来的行中前进或后退一行或多行,这就是游标的用途所在。
是什么
游标(cursor)是一个存储在DBMS服务器上的数据库查询, 它不是一条SELECT语句,而是被该语句检索出来的结果集。
选项和特性
能够标记游标为只读,使数据能读取,但不能更新和删除。
能控制可以执行的定向操作(向前、向后、第一、最后、绝对位置、相对位置等)。
能标记某些列为可编辑的,某些列为不可编辑的。
规定范围,使游标对创建它的特定请求(如存储过程)或对所有请求可访问。
指示DBMS对检索出的数据(而不是指出表中活动数据)进行复制,使数据在游标打开和访问期间不变化。
说明:游标与基于Web的应用
使用游标
步骤:
在使用游标前,必须声明(定义)它。这个过程实际上没有检索数据,它只是定义要使用的SELECT语句和游标选项。
一旦声明,就必须打开游标以供使用。这个过程用前面定义的SELECT语句把数据实际检索出来。
对于填有数据的游标,根据需要取出(检索)各行。
在结束游标使用时,必须关闭游标,可能的话,释放游标(有赖于具体的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 | ||
distinct
它指示数据库只返回不同的值。
eg:SELECT DISTINCT vend_id FROM Products;
警告:不能部分使用 DISTINCT
DISTINCT关键字作用于所有的列,不仅仅是跟在其后的那一列。例如,你指定SELECT DISTINCT vend_id, prod_price,除非指定的两列完
全相同,否则所有的行都会被检索出来。