第1章 了解SQL
1.1 数据库基础
1.1.1 什么是数据库
- 数据库
- 以某种有组织的方式存储的数据集合
- 保存有组织的数据的容器(通常是一个文件或一组文件)
- 数据库软件
- DBMS-数据库管理系统
- 使用DBMS访问数据库
1.1.2 表
- 表
- 是一种结构化的文件,用来存储某种特定类型的数据
- 某种特定类型数据的结构化清单
- 存储在表中的数据是一种类型或一个清单,不应该在同一个表中有两种类型或两个清单
- 表名用来标识自己,名字是唯一的
- 相同数据库中不能使用相同的表名,但在不同的数据库中可以使用相同的表名
- 模式
- 定义了数据在表中如何存储
- 用来描述数据库中特定的表以及整个数据库和其中表的关系
- 关于数据库和表的布局及特性的信息
1.1.3 列和数据类型
- 列
- 表由列组成,列中存储着表中某部分的信息
- 表中的一个字段,所有表都是有一个或者多个列组成的
- 正确地将数据分解分为多个列很重要
- 数据类型
- 所容许的数据的类型,每个表列都有响应的数据类型,限制(或容许)该列中存储的数据
1.1.4 行
- 行
- 表中的一个记录
- 行 = 数据库记录
1.1.5 主键
- 主键
- 一列(或一组列),其值能够唯一区分表中的每个行
- 应该总是定义主键,便于数据操纵和管理
- 任意两行都不具有相同的主键值
- 表中任何列都可以作为主键,主要它满足一下条件
- 每个行都必须具有一个主键值(主键列不允许NULL值)
- 通常定义在表的一列上,但也可以使用多个列作为主键
- 好习惯
- 不更新主键列中的值
- 不重用主键列的值
- 不在主键列中使用可能会更改的值
1.2 什么是SQL
- SQL
- 结构化查询语言(Structured Query Language)
- 专门用来与数据库通信的语言
- 优点
- 不是某个特定数据库供应商专有的语言,通用性
- 简单易学
- 强有力,灵活,可以进行非常复杂和高级的数据库操作
- 任意两个DBMS实现的SQL都不完全相同,不是完全可移植的,本书针对MySQL
1.3 动手实践
- 附录B
B.1 样例表 - 随身物品推销商使用的订单录入系统
- 管理供应商
- 管理产品目录
- 管理顾客列表
- 录入顾客订单
表的描述
6个表,表的列出顺序是因为它们之间的依赖关系
vendors表
- 存储销售产品的供应商,每个供应商为一个记录。供应商列用来匹配产品和供应商
- 所有表都应该有主键,这个表使用vend_id作为主键,vend_id为一个自动增量字段
列 | 说明 |
---|---|
vend_id | 唯一的供应商ID |
vend_name | 供应商名 |
vend_address | 供应商的地址 |
vend_city | 供应商的城市 |
vend_state | 供应商的州 |
vend_zip | 供应商的邮政编码 |
vend_country | 供应商的国家 |
- products表
- products表包含产品目录,每行一个产品,每个产品有唯一的ID(prod_id列),通过vend_id(供应商的唯一ID)关联到它的供应商
- 所有表都应该有主键,这个表使用prod_id列作为主键
- 为实施引用完整性,应该在vend_id上定义一个外键,关联到vendors的vend_id
列 | 说明 |
---|---|
prod_id | 唯一的产品ID |
vend_id | 产品供应商ID(关联到vendors表中的vend_id) |
prod_name | 产品名 |
prod_price | 产品价格 |
prod_desc | 产品描述 |
- customers表
- customers表存储所有顾客的信息,每个顾客有唯一的ID(cust_id列)
- 所有表都应该有主键,这个表使用cust_id列作为主键,cust_id是一个自动增量的字段
列 | 说明 |
---|---|
cust_id | 唯一的顾客ID |
cust_name | 顾客名 |
cust_address | 顾客的地址 |
cust_city | 顾客的城市 |
cust_state | 顾客的州 |
cust_zip | 顾客的邮政编码 |
cust_country | 顾客的国家 |
cust_contact | 顾客的联系名 |
cust_email | 顾客的联系email地址 |
- orders表
- orders表存储顾客订单(但不是订单细节),每个订单唯一的编号(order_num列),订单用cust_id列(它关联到customer表的顾客唯一ID)与响应的顾客关联
- 所有表都应该有主键,这个表使用order_num列作为主键,order_num是一个自动增量的字段
- 为实施引用完整性,应该在cust_id上定义一个外键,关联到customers的cust_id
列 | 说明 |
---|---|
order_num | 唯一订单号 |
order_data | 订单日期 |
cust_id | 订单顾客ID(关联到customers表的cust_id) |
- orderitems表
- orderitems表存储每个订单中的实际物品,每个订单的每个物品占一行,对orders表中的一行,orderitems中有一行或多行,每个订单物品有订单号加订单物品(第一个物品、第二个物品等)唯一标识。订单物品通过order_num列(关联到orders中订单的唯一ID)与它们响应的订单相关联,每个订单项包含订单物品的产品ID(它关联物品到products表)
- 所有表都应该有主键,这个表使用order_num和order_item作为其主键
- 为实施引用完整性,应该在order_num上定义一个外键,关联到orders的order_num,在prod_id定义外键,关联到products的prod_id
列 | 说明 |
---|---|
order_num | 订单号(关联到orders表的order_num) |
order_item | 订单物品号(在某个订单中的顺序) |
prod_id | 产品ID(关联到products表的prod_id) |
quantity | 物品数量 |
item_price | 物品价格 |
- productnotes表
- productnotes表存储于特定产品有关的注释信息,并非所有产品都有相关的注释,而有的产品可能有许多相关的注释
- 所有表都应该有主键,这个表使用note_id作为其主键
- 列note_text必须为FULLTEXT搜索进行索引
- 由于这个表使用全文本搜索,因此必须指定ENGINE=MyISAM
列 | 说明 |
---|---|
note_id | 唯一注释ID |
prod_id | 产品ID(对应于products表中的prod_id) |
note_date | 增加注释的日期 |
note_text | 注释文本 |
B.2 创建样例表
下载数据:https://www/forta.com/books/0672327120/
- 创建一个新数据源
- 保证选择新数据源
- 执行create.sql脚本
- 重复前面的步骤,用populate.sql文件填充各个新表
第2章 MySQL简介
2.1 什么是MySQL
- MySQL
- 是一种DBMS,数据库软件
- 广泛使用,原因:
- 成本 - MySQL是开源的,可以免费使用(甚至可以免费修改)
- 性能 - MySQL执行很快
- 可信赖 - 很多公司,站点都用MySQL来处理自己的重要数据
- 简单 - MySQL很容易安装和使用
2.1.1 客户机-服务器软件
- DBMS
- 分两类,一类为基于共享文件系统的DBMS,另一类为基于客户机-服务器的DBMS
- MySQL是基于客户机-服务器的数据库
- 服务器部分是负责所有数据访问和处理的一个软件,运行在数据库服务器上,与数据文件打交道的只有服务器软件,数据添加、删除和更新都由服务器软件完成
- 客户机是与用户打交道的软件
2.1.2 MySQL版本
- DBMS版本
- 当前版本为5
- 版本4:InnoDB引擎,增加事物处理(第26章),并(第17章),改进全文本搜索(第18章)的支持
- 版本4.1:对函数库、子查询(第14章)、集成帮助等的重要增加
- 版本5:存储过程(第23章)、触发器(第25章)、游标(第24章)、视图(第22章)等
2.2 MySQL工具
2.2.1 mysql命令行使用程序
- 指定登录名:mysql -u ben
- 指定用户名、主机名、端口和口令:mysql -u ben -p -h myserver -P 9999
- 完整的参数列表:mysql —help
- 命令输入在mysql>之后
- 命令用 ; 或 \g 结束,仅按enter不执行命令
- 输入help或 -h 获得帮助
- 获得特定命令的帮助 如help select
- 输入quit或exit退出命令行实用程序
2.2.2 MySQL Administrator
- MySQL Administrator(MySQL管理器)是一个图形交互客户机,简化MySQL服务器的管理
- key points:
- Server Information(服务器信息)显示客户机和被连接的服务器的状态和版本信息
- Server Control(服务控制)允许停止和启动MySQL以及指定服务器特性
- User Administration(用户管理)用来定义MySQL用户、登录和权限
- Catalogs(目录)列出可用的数据库并允许创建数据库和表
2.2.3 MySQL Query Browser
- MySQL Query Browser是一个图形交互客户机,编写和执行MySQL命令
第3章 使用MySQL
3.1 连接
- MySQL有自己的用户列表,用户间的权限可能不同
- MySQL Administrator 的Users视图可直接定义新用户,包括赋予口令和访问权限
- 主机名+端口+用户名+口令
3.2 选择数据库
- 使用USE关键字 (关键字:作为MySQL的保留字,不要用关键字命名一个表和列。)
- USE crashcourse (选择crashcourse数据库,不返回任何结果)
3.3 了解数据库和表
- SHOW DATABASES(返回可用数据库的一个列表)
- SHOW TABLES(返回当前选择的数据库内可用表的列表)
- SHOW COLUMNS FROM customers; (显示表列)
- 对每个字段返回一行,行中包括字段名、数据类型、是否允许NULL、键信息、默认值以及其他信息(如字段cust_id的auto_increment)
- 自动增量:某些表列需要唯一值,在每个行添加到表中时,MySQL自动地为每个行分配下一个可用编号,不用在添加一行时手动分配唯一值。在CREATE语句创建表时定义(第21章)
- DESCRIBE是SHOW COLUMNS FROM的快捷方式,DESCRIBE customers 与 SHOW COLUMNS FROM customers 等价
- SHOW STATUS (显示服务器状态信息)
- SHOW CREATE DATABASE和SHOW CREATE TABLE (分别用来显示创建特定数据库或表的MySQL语句)
- SHOW GRANTS (显示授予用户(所有用户或特定用户)的安全权限)
- SHOW ERRORS和SHOW WARNINGS (显示服务器错误或警告消息)
- HELP SHOW (显示所有允许的SHOW语句)
- MySQL新增内容:INFORMATION_SCHEMA,获得和过滤模式信息
第4章 检索数据
4.1 SELECT语句
- 从一个表或多个表中检索信息
- 使用SELECT时,至少给出两条信息:想选择什么,以及从什么地方选择
4.2 检索单个列
1 | # 从products表中检索一个名为prod_name的列,返回的数据是无序的 |
- 多条语句用分号分隔,在每一条语句后加分号没有坏处
- SQL语句不区分大小写,SELECT=Select,一般对关键字使用大写,对列和表明使用小写,易于阅读和调试
- 在处理SQL语句时,所有空格被忽略,SQL语句可以在一行给出,也可以分成许多行,多行更容易阅读和调试
4.3 检索多个列
- 使用相同的SELECT语句,在SELECT后给出多个列名,列名之间必须以逗号分隔,但最后一个列名后不加逗号,否则报错
1 | SELECT prod_id, prod_name, prod_price |
- SQL语句一般返回原始的、无格式的数据
- 数据的格式化是一个表示问题,而不是检索问题,表示(对齐和数值)一般在显示该数据的应用程序中规定,一般很少使用实际检索出的原始数据
4.4 检索所有列
1 | # 使用通配符 * |
- 如果给定一个通配符 * ,则返回表中所有列,列的顺序一般是列在表定义中出现的顺序,但表的模式的变化(如添加和删除列)可能会导致顺序的变化
- 使用通配符省事,但会降低检索和应用程序的性能
- 使用通配符优点,可以检索出名字未知的列
4.5 检索不同的行
1 | # 只返回不同的vend_id行 |
- 使用DISTINCT关键字只返回不同的值,放在列名的前面
- 不能部分使用DISTINCT,DISTINCT应用于所有列而不仅是前置它的列
4.6 限制结果
- 使用LIMIT语句返回前几行
1 | # 返回不多于5行 |
- 指定要检索的开始行和行数
1 | # 返回从行5开始的5行 |
- LIMIT 5, 5返回从行5开始的5行,第一个数为开始位置,第二个数为要检索的行数
- 带一个值的LIMIT总是从第一行开始,给出的数为返回的行数
- 第一行是行0,LIMIT 1, 1将检索出第二行而不是第一行
- LIMIT中指定要检索的行数为检索的最大行数
- MySQL5支持LIMIT 4 OFFSET 3 与 LIMIT 3, 4等价,从行3开始取4行
4.7 使用完全限定的表名
- 完全限定的名字:同时使用表名和列字
1 | SELECT products.prod_name # 完全限定的列名 |
1 | SELECT products.prod_name # 完全限定的列名 |
第5章 排序检索数据
- SELECT语句的ORDER BY 子句
5.1 排序数据
1 | SELECT prod_name |
以上输出数据没有特定的顺序,如果不排序,一般会以它在底层表中出现的顺序显示,这可以是数据最初添加到表中的顺序,但是,如果数据后来进行过更新或删除,则此顺序将会受到MySQL重用回收存储空间的影响。
子句,SQL语句由子句构成,有些子句是必需的,而有的是可选的,一个子句通常由一个关键字和所提供的的数据组成,如SELECT语句的FROM子句。
ORDER BY子句取一个或多个列的名字,据此对输出进行排序。
1 | SELECT prod_name |
- 通常ORDER BY子句中使用的列为显示所选择的列,但用非检索列的列排序数据也是完全合法的。
5.2 按多个列排序
- 按多个列排序,只要指定列名,列名之间用逗号分开即可。
1 | # 首先按价格,再按名称排序 |
5.3 指定排序方向
- 默认是生序排序,无须指定关键字,也可以指定升序关键字ASC
- 降序排序需要指定DESC关键字。
1 | # 降序排序 |
1 | # prod_price降序排序, prod_name 升序排序 |
- 在多个列上降序排序,必须对每个列指定DESC关键字。
大小写问题,MySQL认为A和a相同。
ORDER BY和LIMIT的组合,能够找出一个列中最高或最低的值。
1 | # 找出价格最高物品的值 |
- ORDER BY在FROM子句之后,LIMIT位于ORDER BY之后,次序不对将报错。
第6章 过滤数据
- 使用SELECT的WHERE子句指定搜索条件。
6.1 使用WHERE子句
- 只检索所需数据需要指定搜索条件,搜索条件也称为过滤条件。
- 在SELECT中,数据根据WHERE子句中指定的搜索条件进行过滤,WHERE子句在表名(FROM子句)之后给出。
1 | # 从products中检索两个列,只返回prod_price值为2.50的行 |
6.2 WHERE子句操作符
- WHERE支持的条件操作符。
操作符 | 说明 |
---|---|
= | 等于 |
<> | 不等于 |
!= | 不等于 |
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
BETWEEN | 在指定的两个值之间 |
6.2.1 检查单个值
1 | # 返回prod_name的值为Fuses的行,不区分大小写,Fuces和fuces匹配 |
1 | # 列出价格小于10美元的所有产品 |
6.2.2 不匹配检查
1 | # 列出不是由供应商制造的所有产品 |
- 何时使用引号:单引号用来限定字符串,如果将值与串类型的列进行比较,则需要限定引号,用来与数值列进行比较的值不用引号。
- <> 和 != 等价。
6.2.3 范围值检查
- 使用BETWEEN操作符,需要两个值,即范围的开始值和结束值,匹配范围内所有的值,包括开始值和结束值。
1 | # 检索价格在5美元到10美元的所有产品 |
6.2.4 空值检查
- 在创建表时,可以指定其中的列可以不包含空值,空值为NULL。
- 空值NULL与字段包含0,空字符串或仅仅包含空格不同。
- IS NULL子句用来检索NULL的列。
1 | # 返回没有价格(空prod_price字段,不是价格为0)的所有产品的行 |
- NULL与不匹配:匹配过滤和不匹配过滤时不返回具有NULL值的行。
第7章 数据过滤
- 组合WHERE子句,NOT和IN操作符。
7.1 组合WHERE子句
- 以ANF子句或OR子句的方式使用多个WHERE子句。
- 操作符:用来联结或改变WHERE子句中的子句的关键字,也称为逻辑操作符。
7.1.1 AND操作符
1 | # 检索由供应商1003制造且价格小于等于10美元的所有产品的名称和价格 |
- AND 用在WHERE子句中的关键字,用来指示检索满足所有给定条件的行。
7.1.2 OR操作符
- OR操作符与AND不同,它指示检索匹配任一条件的行。
1 | # 检索由供应商1002或1003制造的任何产品 |
- OR 用在WHERE子句中的关键字,用来指示检索匹配任一给定条件的行。
7.1.3 计算次序
- WHERE可包含任意数目的AND和OR操作符,允许两者结合以进行复杂和高级的过滤。
- AND的计算优先级比OR高,使用圆括号明确地分组相应的操作符。
1 | # 检索由供应商1002或1003制造的任何产品,并且价格大于等于10美元的行 |
- 在WHERE子句中,任何时候使用AND和OR操作时,都要使用圆括号明确地分组操作符,使用圆括号没有坏处,可以消除歧义。
7.2 IN操作符
- 圆括号在WHERE子句中还有另外一种用法,IN操作符用来指定条件范围,范围中的每个条件都可以进行匹配,IN取合法值的由逗号分隔的清单,全都在圆括号中。
1 | # 检索供应商1002和1003制造的所有产品 |
- IN操作符完成与OR相同的功能。
1
2
3
4
5# 检索供应商1002和1003制造的所有产品
SELECT prod_name, prod_price
FROM products
WHERE vend_id = 1002 OR vend_id = 1003
ORDER BY prod_name;
- IN操作符的优点:
- 在使用长的合法选项清单时,IN操作符的语法更清楚且更直观
- 计算次数更容易管理
- 比OR操作符执行更快
- 最大的优点是可以包含其他SELECT语句,能够更加动态地建立WHERE子句
7.3 NOT操作符
- NOT操作符有且只有一个功能,否定它之后所跟的任何条件。
1 | # 匹配1002和1003之外的供应商 |
- 与IN操作符联合使用时,NOT使找出与条件列表不匹配的行。
第8章 用通配符进行过滤
8.1 LIKE操作符
- 通配符:用来匹配值的一部分的特殊字符。
- 搜索模式:由字面值、通配符或两者组合构成的搜索条件。
- 在搜索子句中使用通配符,必须使用LIKE操作符,LIKE指示后跟的搜索模式利用通配符匹配而不是直接相等匹配进行比较。
8.1.1 百分号(%)通配符
- % 表示任何字符出现的任意次数。
1 | # 检索任意jet起头的词,%告诉MySQL接受jet之后的任意字符,不管它有多少字符 |
- 区分大小写:搜索是可以区分大小写的。
- 通配符可以在搜索模式中任意位置使用,并且可以使用多个通配符。
1 | # 匹配任何位置包含文本anvil的值 |
1 | # 匹配以s起头以e结尾的所有产品 |
- % 还可以匹配0个字符。%代表搜索模式中给定位置的0个、1个或多个字符。
- 注意尾空格,尾空格可能会干扰通配符匹配,例如anvil后有一个或多个空格时,则子句
WHERE prod_name LIKE '%anvil'
将不会匹配它们,因为在最后有空格,一个简单的方法是在搜索模式最后附加一个%,一个更好的方法是使用函数(第11章)去掉首尾空格。 - 注意NULL,%通配符不能匹配值为NULL的行。
8.1.2 下划线(_)通配符
- 下划线只匹配单个字符而不是多个字符。
1 | # (_)只匹配一个字符 |
8.2 使用通配符的技巧
- 通配符搜索的处理一般要比前面讨论的其他搜索所花时间更长。
- 技巧:
- 不要过度使用通配符。
- 除非有必要,否则不要把它们用在搜索模式的开始处,因为置于开始处是最慢的。
- 仔细注意通配符的位置。
第9章 用正则表达式进行搜索
9.1 正则表达式介绍
- 正则表达式:用来匹配文本的特殊的串(字符集合)。
- 更多参考《正则表达式必知必会》。
9.2 使用MySQL正则表达式
- MySQL仅支持正则表达式实现的一个很小的子集。
9.2.1 基本字符匹配
1 | # 检索列prod_name包含1000的所有行 |
1 | # .是表示匹配任意一个字符,因此可以匹配1000和2000 |
- LIKE和REGEXP比较。
1 | # 不返回数据 |
1 | # 检索列prod_name包含1000的所有行 |
- LIKE匹配整个列,如果被匹配的文本在列值中出现,LIKE将不会找到它,除非使用通配符。
- 而REGEXP在列值内进行匹配,如果被匹配的文本在列值中出现,REGEXP将会找到它,响应的行将被返回。
- 匹配不区分大小写,为区分大小写,可使用BINARY关键字,如
WHERE prod_name REGEXP BINARY 'JetPack .000'
。
9.2.2 进行OR匹配
- 为检索两个串之一,使用|。
1 | # | 表示OR操作,表示匹配其中之一,因此1000和2000都匹配 |
- 可以给出两个以上的OR条件,例如
'1000|2000|3000'
将匹配1000或2000或3000。
9.2.3 匹配几个字符之一
- 使用一组用[]括起来的字符即可。
1 | # [123]表示匹配1或2或3,因此,1 ton和2 ton都匹配 |
- [] 是另一种形式的OR语句,
[123] Ton
是[1|2|3] Ton
的缩写。 - 需要用[]来定义OR语句。
1 | # 表示'1'或'2'或'3 ton' |
- 需要把字符|括在一个集合里,否则它将应用于整个串。
- 字符集合也可以被否定,即它将匹配除指定字符外的任何东西,在集合的开始处放置一个^即可,例如123匹配除1、2或3外的任何东西。
9.2.4 匹配范围
- 集合可用来定义要匹配的一个或多个字符。例如
[0123456789]
将匹配数字0到9,可使用-
来定义一个范围,简化为[0-9]。[a-z]匹配任意字母字符。
1 | # [1-5]表示匹配1到5, 5 ton是一个匹配 |
9.2.5 匹配特殊字符
- 加前导\\匹配特殊字符
.、[]、|、_
。\\_
表示查找_
,\\.
表示查找.
。这种处理称为转义。
1 | # 使用 \\. 匹配 . |
\\
也用来引用元字符(具有特殊含义的字符)。
元字符 | 说明 |
---|---|
\\f |
换页 |
\\n |
换行 |
\\r |
回车 |
\\t |
制表 |
\\v |
纵向制表 |
- 为了匹配反斜杠(\)字符本身,需要使用
\\\
- 多数正则表达式实现使用单个反斜杠转义特殊字符,以便能使用这些字符本身,但MySQL要求两个反斜杠实现转义(MySQL解释一个,正则表达式库解释另一个)。
9.2.6 匹配字符类
- 存在找出你自己经常使用的数字、所有字母字符或所有数字字母字符等的匹配。使用预定义的字符集,称为字符类。
表9-2 字符类
类 | 说明 |
---|---|
[:alnum:] |
任意字母和数字(同[a-aA-Z0-9] ) |
[:alpha:] |
任意字母(同[a-zA-Z] )] |
[:blank:] |
空格和制表(同[\\t] ) |
[:cntrl:] |
ASCII控制字符(ASCII 0到31和127) |
[:digit:] |
任意数字(同[0-9] ) |
[:graph:] |
与[:print:] 相同,但不包含空格 |
[:lower:] |
任意小写字母(同[a-z] ) |
[:print:] |
任意可打印字符 |
[:punct:] |
既不在[:alnum:] 又不在[:cntrl:] 中的任意字符 |
[:space:] |
包括空格在内的任意空白字符(同[\\f\\n\\r\\t\\v] ) |
[:upper:] |
任意大写字母(同[A-Z] ) |
[:xdigit:] |
任意十六进制数字(同[a-fA-F0-9] ) |
9.2.7 匹配多个实例
元字符 | 说明 |
---|---|
* | 0个或多个匹配 |
+ | 1个或多个匹配(等于{1, }) |
? | 0个或1个匹配(等于{0,1}) |
{n} | 指定数目的匹配 |
{n, } | 不少于指定数目的匹配 |
{n, m} | 匹配数目的范围{m不超过255} |
1 | # \\(匹配),[0-9]匹配任意数字,sticks?匹配stick和sticks(s后的?使s可选,因为?匹配它前面的任何字符的0次或1次出现),没有?,匹配stick和sticks会非常困难 |
- 以下匹配连在一起的4位数字
1 | # [:digit:] 匹配任意数字,{4}要求它前面的字符(任意数字)出现4次 |
1 | # 与上例等价 |
9.2.8 定位符
- 匹配特定位置的文本。
元字符 | 说明 |
---|---|
^ | 文本的开始 |
$ | 文本的结尾 |
[[:<:]] | 词的开始 |
[[:>:]] | 词的结尾 |
1 | # 使用^定位符找出以一个数(包括小数点开始的数)开始的所有产品 |
- ^还可以在集合中[]用来否定该集合。
- 使REGEXP起类似LIKE的作用,通过用^开始每个表达式,用$结束每个表达式,可以使REGEXP的作用与LIKE一样。
- 可以在不使用数据库表的情况下用SELECT来测试正则表达式,REGEXP总是返回0(不匹配)或者1(匹配)。如
SELECT 'hello' REGEXP '[0-9]';
,返回0。
第10章 创建计算字段
10.1 计算字段
- 存储在数据库表中的数据一般不是应用程序所需要的格式,直接从数据库中检索出转换、计算或格式化过的数据,称为计算字段。
计算字段是运行SELECT语句是创建的。
字段,基本上与列的意思相同,不过数据库列一般称为列,而术语字段通常用在计算字段的连接上。
- 客户机与服务器的格式,可在客户机和服务器上完成转换和格式化工作,但在服务器上比客户机中要快得多。
10.2 拼接字段
- 拼接,将值联结到一起构成单个值。
- 在SELECT语句中,用Concat()函数来拼接两个列。
- MySQL的不同之处,多数DBMS使用+或||来实现拼接,MySQL则使用Concat()函数来实现。
1 | # 返回vend_name(vend_country)字段 |
- 删除数据右侧多于的空格整理数据,使用RTrim。
1 | # 拼接前使RTrim()函数删除vend_name和vend_country右侧的空格 |
LTrim(),去掉串左边的空格,Trim(),去掉左右两边的空格。
使用别名,SELECT语句拼接地址字段没有名字,需要使用别名(alias)表示一个字段或值,用AS关键字赋予。
1 | # 使用AS vend_title指定计算字段的列名 |
- 别名的其他用途,在实际的表列名包含不符合规定的字符(如空格)时重新命名它,在原来的名字含混或容易误解时扩充它。
- 别名,有称为导出列(derived column)。
10.3 执行算术计算
- 对检索出的数据进行算术运算。
1 | # 汇总物品的价格(单价乘以订购数量),expanded_price为一个计算字段 |
- MySQL支持的基本算术运算符,圆括号可用来区分优先顺序。
操作符 | 说明 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
- 测试计算,可以省略FROM子句以便简单地访问和处理表达式,例如
SELECT 3*2
将返回 6,SELECT Trim(' abc ')
将返回abc,SELECT Now()
返回当前日期和时间。
第11章 使用数据处理函数
11.1 函数
- 能运行在多个系统上的代码称为可移植的。
- 函数的可移植性不强。
11.2 使用函数
- 大多数SQL实现支持以下类型的函数。
- 用于处理文本串(如删除或填充值,转换值为大写或小写)的文本函数。
- 用于在数值数据上进行算术操作(如返回绝对值,进行代数计算)的数值函数。
- 用于处理日期和时间值并从这些值中提取特定成分(例如,返回两个日期之差,检查日期有效性等的日期和时间函数。
- 返回DBMS正使用的特殊信息(如返回用户登录信息,检查版本细节)的系统函数。
11.2.1 文本处理函数
- Upper()函数
1 | # 返回vend_name和vend_name大写的一个计算字段 |
- 常用文本处理函数。
函数 | 说明 |
---|---|
Left() | 返回串左边的字符 |
Length() | 返回串的长度 |
Locate() | 找出串的一个子串 |
Lower() | 将串转换为小写 |
LTrim() | 去掉串左边的空格 |
Right() | 返回串右边的字符 |
RTrim() | 去掉串右边的空格 |
Soundex() | 返回串的SOUNDEX值 |
SubString() | 返回子串的字符 |
Upper() | 将串转换为大写 |
SOUNDEX,将任何文本串转换为描述其语音表示的字母数字模式的算法,其考虑了类似的发音字符和音节,使得能对串进行发音比较而不是字母比较。
例如customers表中有一个顾客Coyote Inc.,其联系名为Y. LEE。但如果这是输入错误,实际应为Y. Lie,按正确的联系名搜索将搜索不到。
1 | # 返回空,因为没有叫Y. Lie的 |
1 | # 返回Y.LEE,因为Y.LEE和Y.Lie发音相似 |
11.2.2 日期和时间处理函数
- 常用的日期和时间处理函数
函数 | 说明 |
---|---|
AddDate() | 增加一个日期(天、周等) |
AddTime() | 增加一个时间(时、分等) |
CurDate() | 返回当前日期 |
CurTime() | 返回当前时间 |
Date() | 返回日期时间的日期部分 |
DateDiff() | 计算两个日期之差 |
Date_Add() | 高度灵活的日期运算函数 |
Date_Format() | 返回一个格式化的日期或时间串 |
Day() | 返回一个日期的天数部分 |
DatOfWeek() | 对于一个日期,返回对应的星期几 |
Hour() | 返回一个时间的小时部分 |
Minute() | 返回一个时间的分钟部分 |
Month() | 返回一个日期的月份部分 |
Now() | 返回当前日期和时间 |
Second() | 返回一个时间的秒部分 |
Time() | 返回一个日期的时间部分 |
Year() | 返回一个日期的年份部分 |
- 日期格式必须为yyyy-mm-dd。其他格式也可,但这是首选的,因为它排除了多义性。
- 使用4位数字的年份更可靠。
1 | # 返回order_date为'2005-09-01'的订单 |
- 存储order_date值为
2005-09-01 11:30:05
时,则WHERE order_date = '2005-09-01'
匹配失败。 - 解决方法是仅将给出的日期和列中的日期部分进行比较,而不是将给出的日期和整个列值进行比较。使用Date(order_date)指示仅提取列的日期部分。
1 | # 更可靠的SELECT语句 |
如果要的是日期,使用Date()。想要的是时间,使用Time()。
检索2005年9月下的所有订单。
1 | SELECT cust_id, order_num |
11.2.3 数值处理函数
- 常用数值处理函数
函数 | 说明 |
---|---|
Abs() | 返回一个数的绝对值 |
Cos() | 返回一个角度的余弦 |
Exp() | 返回一个数的指数值 |
Mod() | 返回除操作的余数 |
Pi() | 返回圆周率 |
Rand() | 返回一个随机数 |
Sin() | 返回一个角度的正弦 |
Sqrt() | 返回一个数的平方根 |
Tan() | 返回一个角度的正切 |
第12章 汇总数据
12.1 聚集函数
- 聚集函数,运行在行组上,计算和返回单个值的函数。
函数 | 说明 |
---|---|
AVG() | 返回某列的平均值 |
COUNT() | 返回某列的行数 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
SUM() | 返回某列值之和 |
12.1.1 AVG()函数
- 可以返回所有列的平均值,也可以返回特定列或行的平均值
1 | # 返回products表中所有产品的平均价格 |
1 | # 返回特定供应商的产品平均价格 |
- AVG只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出,为了获得多个列的平均值,必须使用多个AVG()函数。
- AVG函数忽略列值为NULL的行。
12.1.2 COUNT()函数
- 确定表中行的数目或符合特定条件的行的数目。
- 两种使用方式:
COUNT(*)
,对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。- COUNT(column),对特定列中具有值的行进行计数,忽略NULL值。
1 | # 对所有行计数 |
1 | # 对只具有电子邮件地址的客户计数 |
- 如果指定列名,则指定列的空值(NULL)被忽略,但如果用的是星号(不指定列名),则不忽略。
12.1.3 MAX()函数
- 返回列中的最大值
1 | # 返回products中的最大的价格 |
- 对非数值数据使用MAX()函数,允许返回任意列中的最大值,包括文本列。
- MAX()函数忽略值为NULL的行。
12.1.4 MIN()函数
- 返回列中的最小值。
1 | # 返回products中的最小的价格 |
- 对非数值数据使用MIN()函数,允许返回任意列中的最小值,包括文本列。
- MIN()函数忽略值为NULL的行。
12.1.5 SUM()函数
- 返回指定列值的和。
1 | # 返回orderitems表包含订单中实际的物品 |
- SUM()函数也可以合并计算值。
1 | # 返回orderitems表中所有物品价格之和 |
- 可以执行多个列上的计算。
- SUM()函数忽略列值为NULL的行。
12.2 聚焦不同值
- 以下内容仅在MySQL 5及后期版本可用。
- 以上5个聚集函数都可以如下使用:
- 对所有行执行计算,指定ALL参数或不给参数(因为ALL是默认的)。
- 只包含不同的值,指定DISTINCT参数。
1 | # 返回特定供应商的 不同价格 的平均值 |
- DISTINCT必须指定列名,COUNT(DISTINCT)会报错,还不能用于计算或表达式。
- DISTINCT用于MIN()和MAX(),可行但没有价值。用不用结果一样。
12.3 组合函数
1 | # 执行了4个聚集计算 |
第13章 分组数据
13.1 数据分组
- 分组,把数据分为多个逻辑组,以便对每个组进行聚集计算。
13.2 创建分组
- 分组时在SELECT语句的 GROUP BY子句中建立的。
1 | # 使用GROUP BY 对每个供应商计算产品数量 |
- GROUP BY 可以包含任意数目的列,这使得能对分组进行嵌套。
- 如果使用了嵌套,数据将在最后规定的分组上进行汇总, 即所有列都一起计算。
- GROUP BY 子句中列出的每个列都必须是检索列或有效的表达式,如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式,不能使用别名。
- 除聚集语句外,SELECT语句中的每个列都必须在GROUP BY 子句中给出。
- 若分组列中药NULL值,NULL值作为一个分组。
GROUP BY在WHERE子句之后,在ORDER BY 子句之前。
使用WITH ROOLUP关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组)的值。
1 | SELECT vend_id, COUNT(*) AS num_prods |
13.3 过滤分组
- WHERE过滤的是行而不是分组。
- 使用HAVING过滤分组,WHERE子句可以用HAVING子句替代。
1 | # 找出两个以上的订单的分组,使用WHERE不起作用 |
- WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤,WHERE排除的行不包括在分组中。
1 | # 列出具有2个及以上、价格为10及以上的产品的供应商 |
13.4 分组和排序
- ORDER BY 与GROUP BY的差别
ORDER BY | GROUP BY |
---|---|
排序产生的输出 | 分组行。但输出可能不是分组的顺序 |
任意列都可以使用(甚至非选择的列也可以使用) | 只可能使用选择列或表达式列,而且必须使用每个选择列表式 |
不一定需要 | 如果与聚集函数一起使用列(或表达式),则必须使用 |
- 一般在使用GROUP BY子句时,应该也给出ORDER BY 子句,这是保证数据正确排序的唯一方法。
1 | # 列出总计订单价格大于等于50的订单号和总订单价格 |
13.5 SELECT子句顺序
子句 | 说明 | 是否必须使用 |
---|---|---|
SELECT | 要返回的列或表达式 | 是 |
FROM | 从中检索数据的表 | 仅在从表选择数据时使用 |
WHERE | 行级过滤 | 否 |
GROUP BY | 分组说明 | 仅在按组计算聚集时使用 |
HAVING | 组级过滤 | 否 |
ORDER BY | 输出排序顺序 | 否 |
LIMIT | 要检索的行数 | 否 |
第14章 使用子查询
14.1 子查询
- 版本要求,MySQL4.1及以上版本。
- 查询,任何SQL语句都是查询,但此术语一般指SELECT语句。
- 子查询,嵌套在其他查询中的查询。
14.2 利用子查询进行过滤
- 把一条SELECT语句返回的结果用于另一条SELECT语句的WHERE子句。
1 | SELECT cust_name, cust_contact |
- 在SELECT语句中,子查询总是从内向外处理。
- 对于能嵌套的子查询的数目没有限制,但太多嵌套会影响性能。
- 列必须匹配,SELECT语句应该具有与WHERE子句中相同数目的列。
- 子查询可以与IN,=,<>等操作符结合使用。
14.3 作为计算字段使用子查询
- 使用子查询的另一方法是创建计算字段。
1 | # 从customers表中检索客户列表 |
- 子查询中的WHERE语句需要使用完全限定列名。
orders.cust_id = customers.cust_id
。这种类型的子查询称为相关子查询,即涉及外部查询的子查询,必须使用这种语法。否则可能出错。
第15章 联结表
15.1 联结
- SQL最强大的功能之一,在数据检索查询的执行中联结表。
15.1.1 关系表
- 关系表的设计就是要保证把信息分解成多个表,一类数据一个表。各表通过某些常用的值(关系)互相关联。
- 外键,某个表的一列,它包含另一个表的主键值,定义了两个表之间的关系。
- 好处:
- 信息不重复,不浪费时间和空间。
- 信息变动,只更新对应表的单个记录,相关表中的数据不用改动。
- 数据无重复,处理更简单。
- 有效地存储和方便地处理。
- 关系数据库的可伸缩性远比非关系数据库要好。
- 可伸缩性,能够适应不断增加的工作量而不失败。
15.1.2 为什么要使用联结
- 联结,用来在一条SELECT语句中关联表。
- 维护引用完整性,仅在关系列中插入合法的数据。
15.2 创建联结
1 | # prod_name, prod_price在products中,而vend_name在vendors中 |
- 在引用的列可能出现二义性时,必须使用完全限定列名。
15.2.1 WHERE子句的重要性
- WHERE作为过滤条件,只包含那些匹配给定条件(联结条件)的行。
- 没有WHERE子句,第一个表中的每个行将与第二个表中的每个行配对,而不管它们逻辑上是否可以配在一起。 笛卡尔积,由没有联结条件的表关系返回的结果为笛卡尔积,检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。又称叉联结。
- 应该保证所有联结都有WHERE子句,否则将返回比想要的数据多得多的数据
15.2.2 内部联结
- 基于两个表之间的相等测试,称为等值联结,也称为内部联结。
- 使用不同语法来明确联结的类型。
1 | # 与前面例子完全相同 |
- ANSI SQL规范首选INNER JOIN 语法。
15.2.3 联结多个表
- SQL对一条SELECT语句中可以联结的表的数目没有限制。首先列出所有表,然后定义表之间的关系。
1 | # 显示订单编号为20005的订单中的物品 |
性能考虑,联结的表越多,性能下降越厉害。
联结表可以替代子查询。
1 | SELECT cust_name, cust_contact |
第16章 创建高级联结
16.1 创建高级联结
- 给列起别名的语法如下。
1 | SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country), ')') AS vend_title |
- 给表名起别名,可以缩短SQL语句,并允许在单条SELECT语句中多次使用相同的表。
1 | SELECT cust_name, cust_contact |
- 表别名只在查询执行中使用,与列别名不一样,表别名不返回到客户机。
16.2 使用不同类型的联结
- 前文都是内部联结,下面介绍自联结、自然联结和外部联结。
16.2.1 自联结
1 | # 查询生产ID为DTNTR的供应商的其他物品 |
- 用自联结而不用子查询,虽然结果相同,但自联结速度更快。
16.2.2 自然联结
- 自然联结排除列多次出现,使每个列只返回一次。
1 | # 通配符只对第一个表使用,所有其他列明确列出,所有没有重复的列被检索出来 |
- 到目前为止 每个内部联结都是自然联结,一般不会用到不是自然联结的内部联结。
16.2.3 外部联结
- 外部联结,联结包含了在相关表中没有关联行的行。
1 | # 内部联结 检索所有客户及其订单 |
1 | # 外部联结 检索所有客户,包括没有订单的客户 |
- 在使用OUTER JOIN语法时,必须使用RIGHT或LEFT关键字指定包括其所有行的表,RIGHT指出的是OUTER JOIN右边的表,而LEFT指出的是OUTER JOIN左边的表。上例使用LEFT OUTER JOIN从FROM 子句的左边表(customers表)中选择所有行。
- 不支持
*=
和=*
的使用。
16.3 使用带聚集函数的联结
1 | # 检索所有客户及每个客户所下的订单数 |
1 | # 使用左外部联结来包含所有客户,包括没有任何下订单的客户 |
16.4 使用联结和联结条件
- 注意所使用的联结条件,一般使用内部联结。
- 保证使用正确的联结条件,否则将返回不正确的数据。
- 应该总是提供联结条件,否则会得出笛卡尔积。
- 使用多个联结时,分别测试每个联结,这将使故障排除更为简单。
第17章 组合查询
17.1 组合查询
- 组合查询,执行多条SELECT语句,并将结果作为单个查询结果集返回,这些组合查询又称并或复合查询。
- 两种情况需要组合查询:
- 在单个查询中从不同的表返回类似结构的数据。
- 对单个表执行多个查询,按单个查询返回数据。
- 组合查询与具有多个WHERE子句条件的单条查询相同。
17.2 创建组合查询
- 用UNION操作符来组合数条SQL查询。
17.2.1 使用UNION
- 给出每条SELECT语句,在各条语句之前放上关键字UNION。
1 | # 使用UNION |
17.2.2 UNION规则
- UNION必须由两条或两条以上的SELECT语句组成,语句之间用UNION分隔。
- UNION中的每个查询必须包含相同的列、表达式或聚集函数(列出次序可以不同)
- 列数据类型必须兼容,类型不必完全相同,但必须是DBMS可以隐含地转换的类型。
17.2.3 包含或取消重复的行
- UNION从查询结果集中自动去除了重复的行。可以使用UNION ALL不去除重复的行。
17.2.4 对组合结果排序
- 在使用UNION组合查询时,只能使用一条ORDER BY子句,必须出现在最后一条SELECT语句之后。
1 | # 使用UNION |
第18章 全文本搜索
18.1 理解全文本搜索
- 两个最常用的引擎MyISAM和InnoDB,前者支持全文本搜索,而后者不支持。
- 如果需要全文本搜索功能,在创建表时选择MyISAM引擎。
- 通配符和正则表达式存在几个重要的限制:
- 性能,通配符和正则表达式通常要求尝试匹配表中所有行,行增加时非常耗时。
- 明确控制,很难明确控制匹配什么和不匹配什么。
- 智能化的结果。
18.2 使用全文本搜索
- 为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改变不断地重新索引。
- 在索引之后,SELECT可与Match()和Against()一起使用以执行搜索。
18.2.1 启用全文本搜索支持
- 在创建表时启用全文本搜索,CRTATE TABLE语句(第21章介绍)接收FULLTEXT子句。
1 | CRTATE TABLE productnotes |
- MySQL根据子句FULLTEXT(note_text)的指示对note_text进行索引。FULLTEXT可以索引单个或者多个列。MySQL自动维护该索引,在增加、更新或删除行时,索引随之自动更新。
- 可以在创建表时指定FULLTEXT,或者在稍后指定(在这种情况下所有已有数据必须立刻索引)。
- 不要在导入数据时使用FULLTEXT,更新索引比较耗时。
18.2.2 进行全文本搜索
- 使用函数Match()和Against()执行全文本搜索,其中Match()指定被搜索的列,Against()指定要使用的搜索表达式。
1 | # 搜索note_text中含rabbit的行 |
- 传递给Match()的值必须与FULLTEXT()定义中的相同,如果指定多个列,则必须列出它们(而且次序正确)。
- 搜索默认不区分大小写,除非使用BINARY关键字。
1 | # 也使用LIKE 搜索note_text中含rabbit的行 |
- LIKE以不那么有用的顺序返回数据,使用全文本搜索以文本匹配的良好程度排序返回数据。全文本搜索的一个重要部分就是对结果排序,具有较高等级的行先返回。
1 | # 全文本搜索排序过程,不包含rabbit的行等级为0,包含rabbit的行中词靠前的行等级高 |
18.2.3 使用查询扩展
- 查询扩展用来设法放宽所返回的全文本搜索结果的范围。
使用查询扩展时,MySQL对数据和索引进行两遍扫描来完成搜索:
- 首先,进行一个基本的全文本搜索,找出与搜索条件匹配的所有行。
- 其次,MySQL检查这些匹配行并选择所有有用的词(如何判定什么有用,什么无用)。
- 再其次,MySQL再次进行全文本搜索,这次不仅使用原来的条件,而且还使用所有有用的词。
利用扩展查询,能找出可能相关的结果,即使它们并不精确包含所查找的词。
- 查询扩展功能只用于版本4.1.1或更高版本。
1 | # 搜索note_text中含rabbit的行 |
- 表中的行越多,使用查询扩展返回的结果越好。
18.2.4 布尔文本搜索
- MySQL支持全文本搜索的另一种形式,称为布尔方式。
- 以布尔方式,可以提供如下内容的细节:
- 要匹配的词;
- 要排斥的词;
- 排列提示;
- 表达式分组;
- 另外一些内容。
- 即使没有FULLTEXT索引也可以使用,但性能比较差。
1 | # 匹配词heavy,但排除包含任何以rope开始的词的行 |
布尔操作符 | 说明 |
---|---|
+ | 包含,词必须存在 |
- | 排除,词必须不出现 |
> | 包含,而且增加等级值 |
< | 包含,而且减少等级值 |
() | 把词组成表达式(允许这些子表达式作为一个组被包含、排除、排列等) |
~ | 取消一个词的排序词 |
* | 词尾的通配符 |
“ ” | 定义一个短语(与单个词的列表不一样,它匹配整个短语以便包含或排除这个短语) |
1 | # 匹配包含词rabbit和bait的行 |
1 | # 没有指定操作符,匹配包含rabbit和bait中的至少一个词的行 |
1 | # 匹配rabbit和carrot,增加前者的等级,降低后者的等级 |
1 | # 匹配safe和combination,降低后者的等级 |
18.2.5 全文本搜索的使用说明
- 在索引全文本数据时,短语被忽略且从索引中排除,短语定义为具有3个及3个以下字符的词(如果需要,这个数目可以更改)。
- MySQL带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时总是被忽略,如果需要,可以覆盖这个列表。
- 许多词出现的频率很高,搜索它们没有用处(返回太多结果),因此,如果一个词出现在50%的行中,则将它作为一个非用词忽略。%50规则不用于 IN BOOLEAN MODE。
- 如果表中的行数少于3,则全文本搜索不返回结果。
- 忽略词中的单引号。例如don’t索引为dont
- 不具有词分隔符的语言不能恰当地返回全文本搜索结果。
- 仅在MyISAM引擎中支持全文本搜索。
- 没有邻近操作符。
第19章 插入数据
19.1 数据插入
- INSERT语句。
- 插入完整的行。
- 插入行的一部分。
- 插入多行。
- 插入某些查询的结果。
19.2 插入完整的行
- 指定表名和被插入到新行中的值。
- 存储到每个表列中的数据在VALUES子句中给出,对每个列必须提供一个值。
- 各个列必须以它们在表定义中出现的次序填充。
1 | # 插入一个新客户到customers表 |
简单但不安全,尽量避免使用,高度依赖于表中列的定义次序,并且还依赖于其次序容易获得的信息,结构变动后各个列可能不能保持相同的次序。
更安全的方法(不过更繁琐),在表名后的括号里明确给出列名。
1 | # 插入一个新客户到customers表 |
- 提供了列名,VALUES必须以其指定的次序匹配指定的列名,不一定按各个列出现在实际表中的次序,即使表的结构改变,仍能正确工作。
- 总是使用列的列表。
- 仔细地给出正确数目的VALUES值。
使用给出列名的这种语法,还可以省略列,可以只给某些列提供值。
- 该列定义为允许NULL值
- 在表定义中给出默认值,这表示如果不给出值,将使用默认值
- 如果对表中不允许NULL值且没有默认值的列不给出值,将会报错
提高整体性能,INSERT操作比较耗时,可以在INSERT和INTO之间添加关键字LOW_PRIORITY,指示降低INSERT的优先级。
19.3 插入多个行
- 使用多条INSERT语句,一次提交它们,每条语句用一个分号结束。
1 | # 插入多个新客户到customers表 |
- 或者,只要每条INSERT语句中的列名和次序相同,可以如下组合各语句。
1 | # 插入多个新客户到customers表 |
- 其中单条INSERT语句有多个值,每组值用一对圆括号括起来,用逗号分隔。此技术可以提高数据库处理的性能,因为用单条INSERT语句处理多个插入比使用多条INSERT语句块。
19.4 插入检索出的数据
- 利用INSERT语句将一条SELEECT语句的结果插入表中,这就是所谓的INSERT SELECT,即由一条INSERT语句和一条SELECT语句组成。
1 | # 从custnew表将所有数据导入到customers表中 |
- INSERT SELECT中的列名,不一定要求列名匹配,使用的是列的位置,SELECT中的第一列(不管其列名)将会用来填充INSERT表列中指定的第一个列。这对于使用不同列名的表中导入数据非常有用。
- INSERT SELECT语句可包含WHERE子句过滤插入的数据。
第20章 更新和删除数据
20.1 更新数据
- UPDATE语句更新(修改)表中的数据。
- 更新表中特定行,使用WHERE子句
- 更新表中所有行
- UPDATE语句的组成。
- 要更新的表
- 列名和它们的新值
- 确定要更新行的过滤条件
1 | # 更新单个列 |
- UPDATE后更要更新的表名。SET用来指定新值被赋予的列。WHERE指定特定的行,没有WHERE子句,将会更新所有行。
- 在更新多个列时,只需要使用单个SET命令,每个 “列=值”对之间用逗号分隔。
1 | # 更新两个列 |
- UPDATE语句可以使用子查询,使得能用SELECT语句检索出的数据更新列数据。
IGNORE关键字,即使发生错误,也继续进行更新,UPDATE IGNORE customers..。
为删除某个列的值,可设置它为NULL值(假如表定义允许NULL值)。
1 | UPDATE customers |
20.2 删除数据
- DELETE语句删除(去掉)数据。
- 从表中删除特定的行,使用WHERE子句
- 从表中删除所有行
1 | # 删除一行 |
- DELETE不需要列名和通配符。
- DELET 删除整行而不是删除列,为了删除指定的列,使用UPDATE语句。
- DELETE从表中删除行,不删除表本身。
- 如果想要删除表中所有的行,不要使用DELETE,可使用TRUNCATE TABLE语句,它完成同样的工作,但速度更快。
20.3 更新和删除的指导原则
- 除非打算更新和删除所有行,否则不要使用不带WHERE子句的UPDATE或DELETE语句。
- 保证每个表都有主键,尽可能像WHERE子句那样使用它。
- 在对UPDATE或DELETE语句使用WHERE子句前,应先使用SELECT进行测试,保证正确过滤。
- 使用强制引用完整性的数据库。
- 没有撤销功能。
第21章 创建和操纵表
21.1 创建表
- 创建表的方法。
- 使用具有交互式管理和创建表的工具
- 使用MySQL语句操纵,使用CREATE TABLE语句
21.1.1 表创建基础
- 创建表,必须给出以下信息。
- 新表的名字,在关键字CREATE TABLE之后给出
- 表列的名字和定义,用逗号分隔
1 | # 创建customers表 |
- SQL对缩进空格等格式化没有规定,推荐采用某种缩进格式。
- 创建表时,指定的表名必须不存在,否则出错。如果表存在,一般首先手工删除表,然后在重建它。如果想仅在表不存在时创建,表名后使用IF NOT EXISTS。
21.1.2 使用NULL值
- 允许NULL值的列允许在插入行时不给出该列的值,不允许NULL值的列在插入或更新行时,该列必须有值。
- 创建表时,NULL为默认设置,如果不指定NOT NULL,则认为指定的是NULL。
- NULL值是没有值,而不是空串
''
,空串是一个有效的值。
21.1.3 主键再介绍
- 主键值必须唯一,如果使用单个列,则它的值必须唯一,如果使用多个列,则这些列的组合值必须唯一。
- 多个列组成的主键,以逗号分隔的列表给出各列名。
1 | # 多个列组成的主键 |
- 主键可以在创建表时定义,也可以在创建表之后定义。
- 主键中不允许NULL值的列,允许NULL值的列不能作为唯一标识。
21.1.4 使用AUTO_INCREMENT
- 设置AUTO_INCREMENT 的列,每当增加一行时自动增量。
- 每个表只允许一个AUTO_INCREMENT 列,而且它必须被索引,可以通过使它成为主键值。
- AUTO_INCREMENT 的列可以在插入时指定一个值,只要它是唯一(至今尚未使用过)即可,该值将被用来替代自动生成的值,后续的增量将开始使用该手工插入的值。
- 确定AUTO_INCREMENT的值,使用SELECT last_insert_id()返回最后一个AUTO_INCREMENT值,然后可以将该值用于其他MySQL语句。
21.1.5 指定默认值
- 默认值用CREATE TABLE语句的列定义中的DEFALUT关键字指定。
1 | # 指定quantity的默认值为1 |
- 不允许使用函数作为默认值,它只支持常量。
- 使用默认值而不是NULL值。
21.1.6 引擎类型
- 如果省略ENGINE=语句,则使用默认引擎(很可能是MyISAM)。
- InnoDB是一个可靠的事物处理引擎,不支持全文本搜索。
- MEMORY在功能上等同于MyISAM,但由于数据存储在内存中,速度很快(适合于临时表)。
- MyISAM是一个性能极高的引擎,它支持全文本搜索,但不支持事物管理。
- 引擎类型可以混用。
- 外键不跨引擎。
- MyISAM最受欢迎。
21.2 更新表
- 使用ALTER TABLE更新表定义,但是,理想状态下,当表中存储数据以后,该表就不应该别更新。
- 使用ALTER TABLE更改表结构,需给出以下信息。
- 在ALTER TABLE之后给出要更改的表名(该表必须存在)。
- 所做更改的列表。
1 | # 给表添加一个名为vend_phone的列,必须明确数据类型 |
1 | # 删除列 |
- 使用ALTER TABLE 定义外键。
1 | ALTER TABLE orderitems |
- 复杂的表结构更改需要手动删除过程,步骤:
- 用新的列布局创建一个新表;
- 使用INSERT SELECT语句从旧表复制数据到新表,如果有必要,可使用转换函数和计算字段;
- 检验包含所需数据的新表;
- 重命名旧表(如果确定,可以删除它);
- 用旧表原来的名字重命名新表;
- 根据需要,重新创建触发器、存储过程、索引和外键。
- 使用ALTER TABLE前应该做一个完整的备份,因为数据表的更改不能撤销。
21.3 删除表
- 使用DROP TABLE 语句。DROP TABLE customers2,删除表没有确认,也不能撤销。
21.4 重命名表
- 使用RENAME TABLE语句。
1 | # 重命名一个表 |
第22章 使用视图
22.1 视图
- 版本要求,MySQL5及之后版本添加了对视图的支持。
- 视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询。
1 | SELECT cust_name, cust_contact |
22.1.1 为什么使用视图
- 重用SQL语句。
- 简化复杂的SQL操作。
- 使用表的组成部分而不是整个表。
- 保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限。
更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。
在视图创建之后,可以用于表基本相同的方式利用他们,可以执行SELECT,过滤和排序,联结,甚至是添加和更新数据的操作。
- 性能问题。视图不包含数据,每次使用视图时,都必须处理查询执行时所需的任一个查询,如果使用多个联结和过滤创建了复杂的视图或者嵌套了视图,可能会发现性能下降得很厉害。
22.1.2 视图的规则和限制
- 与表一样,视图必须唯一命名。
- 对于可创建的视图数目没有限制。
- 为了创建视图,必须具有足够的访问权限。这些限制通常有数据库管理人员授予。
- 视图可以嵌套。
- ORDER BY 可以用在视图中,但如果从该视图检索数据SELECT中也含有ORDER BY,那么该视图中的ORDER BY 将被覆盖。
- 视图不能索引,也不能有关联的触发器或默认值。
- 视图可以和表一起使用。
22.2 使用视图
- 视图用CREATE VIEW语句来创建。
- 使用SHOW CREATE VIEW viewname,来查看创建视图的语句。
- 用DROP删除视图,其语法为DROP VIEW viewname。
- 更新视图时,可以先用DROP再用CREATE,也可以直接用CREATE OR REPLACE VIEW。如果要更新的视图不存在,则第2条更新语句会创建一个视图,如果要更新的视图存在,则第2条语句会替换原有视图。
22.2.1 利用视图简化复杂的联结
- 视图最常用的应用之一是隐藏复杂的SQL。
1 | # 创建名为productcustomers的视图,联结三个表,以返回以订购了任意产品的所有客户的列表 |
- 创建可重用的视图是一种好方法。
22.2.2 用视图重新格式化检索出的数据
- 视图的另一常见用途是重新格式化检索出的数据。
1 | # 返回供应商名和位置(来自第10章) |
- 假如要经常使用这个格式的结果,不必在每次需要时执行联结,创建一个视图,每次需要时使用它即可。
1 | # 创建视图 返回供应商名和位置 |
22.2.3 用视图过滤不想要的数据
- 视图也可以使用WHERE子句过滤数据。
1 | # 创建视图,排除没有电子邮件地址的用户 |
- 如果从视图检索数据时使用了一条WHERE子句,则两组子句(一组在视图中,另一组是传递给视图的)将自动组合。
22.2.4 使用视图与计算字段
- 视图对于简化计算字段的使用特别有用。
1 | # 检索某个特定订单中的物品,计算每种物品的总价格(来自第10章) |
22.2.5 更新视图
- 视图的数据是否可以更新是视情况而定。
- 通常,视图是可以更新的,更新一个视图将更新其基表(视图本身没有数据)。
- 但是,并非所有视图都是可更新的,如果不能正确地确定被更新的基数据,则不允许更新。
- 如果视图定义中有以下操作,将不能更新:
- 分组(GROUP BY 和HAVING)
- 联结
- 子查询
- 并
- 聚集函数(MIN()、COUNT()、SUM() 等)
- DISTINCT
- 导出(计算)列
- 视图主要用于数据检索(SELECT),很少用于更新(INSERT、UPDATE和DELETE)。
第23章 使用存储过程
23.1 存储过程
- MySQL添加了对存储过程的支持,支持MySQL5及以后的版本。
- 存储过程,就是为以后的使用而保存的一条或多条MySQL语句的集合,可将其视为批文件。
23.2 为什么要使用存储过程
- 存储过程的好处:
- 通过把处理封装在容易使用的单元中,简化复杂的操作。
- 由于不要求反复建立一系列处理步骤,保证了数据的完整性,所有开发人员和应用程序都使用同一的存储过程,则所使用的代码都是相同的。 防止错误,需要执行的步骤越多,出错的可能性就越大。
- 简化对变动的管理,如果表名、列名或业务逻辑有变化,只需要更改存储过程的代码。通过对存储过程限制对基础数据的访问保证了安全性。
- 提高性能,使用存储过程比适用单独的SQL语句要快。
- 总结:简单,安全,高性能。
- 存储过程的缺陷:
- 编写比基本的SQL语句复杂。
- MySQL将编写和执行存储过程的安全和访问区分开来,你可能没有创建存储过程的安全访问权限。
- 不能编写存储过程,但仍然可以使用。
23.3 使用存储过程
23.3.1 执行存储过程
- 调用,CALL,接受存储过程的名字以及需要传递给它的任意参数。
1 | # 执行名为productpricing的存储过程,返回产品的最低、最高和平均价格 |
- 存储过程可以显示结果,也可以不显示结果。
23.3.2 创建存储过程
1 | # 返回平均价格的存储过程,名为productpricing,没有参数 |
- 因为存储过程的语句结束分隔符也为
;
,需要临时更改语句结束分隔符。除 \ 符号外,任何字符都可以作为语句分隔符。
1 | # 告诉命令行使用 // 作为新的语句结束分隔符 |
1 | # 调用存储过程 |
23.3.3 删除存储过程
- 存储过程创建后,被保存在服务器上以供使用,直至被删除。
- 删除存储过程,
DROP PROCEDURE productpricing;
。存储过程名后不带(),只给出存储过程名。 - 仅当存在时删除,
DROP PROCEDURE IF EXISTS productpricing
。
23.3.4 使用参数
- 一般地,存储过程并不显示结果,而是把结果返回给你指定的变量。
- 变量,内存中一个特定的位置,用来临时存储数据。
1 | # 以下是productpricing的修改版本,如果不事先删除此存储过程,则不能再次创建它 |
- 每个参数必须具有指定的类型,关键字OUT指出相应的参数用来从存储过程传出一个值,返回给调用者。
- IN(传递给存储过程),OUT(从存储过程传出),INTO(对存储过程传入和传出)。
- 记录集是不允许的类型,不能通过一个参数返回多个行和列。
1 | # 调用此修改过的存储过程,需指定三个变量名 |
- MySQL的所有变量都必须以@开始。
- 使用IN和OUT参数
1 | # 使用IN和OUT参数,ordertotal接受订单号并返回该订单的合计 |
23.3.5 建立智能存储过程
- 包含业务规则和智能处理的存储过程。
1 | # name: ordertotal |
23.3.6 检查存储过程
- 显示用来创建一个存储过程,的CREATE语句。
SHOW CREATE PROCEDURE ordertotal
。 - 获得包括何时、由谁创建等详细信息的所有存储过程列表,使用
SHOW PROCEDURE STATUS
。 - 使用LIKE指定一个过滤模式,列出指定的存储过程,使用
SHOW PROCEDURE STATUS LIKE 'ordertotal'
。
第24章 使用游标
24.1 存储过程
- 版本MySQL5及之后的版本支持。
- 使用游标的原因,需要在检索出来的行中前进或后退一行或多行。
- 游标是一个存储在MySQL服务器上的数据库查询,它不是一条SELECT语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。
- 游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或作出更改。
- MySQL的游标只能用于存储过程(和函数)。
24.2 使用游标
- 使用前需要声明(定义)游标。
- 声明后,需要打开游标以供使用。
- 对于填有数据的游标,根据需要取出(检索)各行。
- 在结束游标使用时,必须关闭游标。
24.2.1 创建游标
- 游标用DECLARE语句创建,并定义响应的SELECT语句,根据需要带WHERE和其他子句。
1 | # 创建名为ordernumbers的游标,使用了可以检索所有订单的SELECT语句 |
- 存储过程处理完成后,游标就消息(因为它局限于存储过程),在定义游标之后,可以打开它。
24.2.2 打开和关闭游标
- 使用OPEN CURSOR语句打开游标。如
OPEN ordernumbers
。在处理OPEN语句时执行查询,存储检索出的数据以供浏览和滚动。 - 关闭游标,
CLOSE ordernumbers
。CLOSE释放游标使用的所有内部内存和资源,游标不需要时应该关闭。 - 隐含关闭,如果不明确关闭游标,将会在到达END语句时自动关闭。
1 | # 创建名为ordernumbers的游标,使用了可以检索所有订单的SELECT语句 |
24.2.3 使用游标数据
使用FETCH语句分别访问它的每一行,FETCH指定检索什么数据(所需的列),检索出来的数据存储在什么地方。它还向前移动游标中的内部行指针,使下一条FETCH语句检索下一行。
从游标中检索单个行。
1 | # 创建名为ordernumbers的游标,使用了可以检索所有订单的SELECT语句 |
- 循环检索数据,从第一行到最后一行。
1 | # 创建名为ordernumbers的游标,使用了可以检索所有订单的SELECT语句 |
- 需设置变量done为真的停止条件。
1 | # 定义了CONTINUE HANDLER,指出当SQLSTATE '02000'出现时,SET done 1, |
DECLARE语句定义的局部变量必须在定义任意游标或句柄之前定义,而句柄必须在游标之后定义。
更详细的游标存储过程样例。
1 | # 创建名为ordernumbers的游标,使用了可以检索所有订单的SELECT语句 |
- 此存储过程不返回数据,但它能够创建和填充另一个表。查看该表,
SELECT * FROM ordertotals
。
第25章 使用触发器
25.1 触发器
- MySQL5或之后的版本支持触发器。
- 希望某条语句(或某些语句)在事件发生时自动执行。
- 触发器是MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于BEGIN和END语句之间的一组语句):
- DELETE
- INSERT
- UPDATE
- 其他MySQL语句不支持触发器。
25.2 创建触发器
- 在创建触发器时,需要给出四条信息:
- 唯一的触发器名
- 触发器关联的表
- 触发器应该响应的活动(DELETE、INSERT或UPDATE)
- 触发器何时执行(处理之前或之后)
触发器在每个表中唯一,在数据库中的两个表可以具有相同名字的触发器。但最好在数据库范围内使用唯一的触发器名。
触发器用CREATE TRIGGER语句创建。
1 | # 创建名为newproduct的触发器,将在INSERT语句执行后执行 |
- 只有表才支持触发器,视图不支持(临时表也不支持)。
- 触发器按每个表每个事件每次地定义,每个表每个事件每次只允许一个触发器,每个表最多支持6个触发器(每天INSERT、UPDATE和DELETE的之前和之后)。
- 单个触发器不能与多个事件或多个表关联,如果你需要对一个INSERT和UPDATE操作执行的触发器,则应该定义两个触发器。
25.3 删除触发器
- 使用DROP TRIGGER 语句。如
DROP TRIGGER newproduct
。 - 触发器不能更新或覆盖,为了修改一个触发器,必须先删除它,然后再重新创建。
25.4 使用触发器
25.4.1 INSERT触发器
- INSERT 触发器在INSERT语句执行之前或之后执行。
- 在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行。
- 在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改被插入的值)。
- 对于AUTO_INCREMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值。
1 | # 创建一个名为neworder的触发器 |
25.4.2 DELETE触发器
- DELETE触发器在DELETE语句执行之前或之后执行。
- 在DELETE触发器代码内,可引用一个名为OLD的虚拟表,访问被删除的行。
- OLD中的值全都是只读的,不能更新。
1 | # 在任意订单被删除前将执行此触发器,它使用一条INSERT语句将OLD中的值(要被删除的订单)保存到archive_orders存档表中 |
- 使用BEGIN 和 END语句的好处是触发器能容纳多条SQL语句。
25.4.3 UPDATE触发器
- UPDATE 触发器在UPDATE语句执行之前或之后执行。
- 在UPDATE触发器代码内,可引用一个名为OLD的虚拟表访问以前的值,引用一个名为NEW的虚拟表访问被新更新的值。
- 在BEFORE UPDATE触发器中,NEW中的值也可以被更新(允许更改被插入的值)。
- OLD中的值全都是只读的,不能更新。
1 | # 保证输入的州名是大写,不管输入是大写还是小写 |
25.4.4 关于触发器的进一步介绍
- 创建触发器可能需要特殊的安全访问权限。但是触发器的执行时自动的。
- 用触发器保证数据的一致性(大小写、格式等)。
- 触发器可以创建审计跟踪,把更改记录到另一个表非常容易。
- 触发器不支持CALL语句。
第26章 管理事务处理
26.1 事务处理
- MyISAM和InnoDB是两种最常使用的引擎,前者不支持明确的事务处理管理,后者支持。
- 事务处理用来维护数据库的完整性,它保证成批的MySQL操作要么完全执行,要么完全不执行。
- 利用事务管理,可以保证一组操作不会中途停止,它们作为整体执行,或者完全不执行。
如果没有发生错误,整组语句提交给数据库表,如果发生错误,则进行回退(撤销)以恢复数据库到某个已知且安全的状态。
事务(transaction):一组SQL语句。
- 回退(rollback):撤销指定SQL语句的过程。
- 提交(commit):将未存储的SQL语句结果写入数据库表。
- 保留点(savepoint):事务处理中设置的临时占位符(placeholder),你可以对它发布回退。
26.2 控制事务处理
- 关键在于将SQL语句分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。
- 使用
START TRANSACTION
来标识事务的开始。
26.2.1 使用ROLLBACK
- 使用ROLLBACK来回退(撤销)MySQL语句。
1 | SELECT * FROM ordertotals; # 显示表ordertotals不为空 |
- ROLLBACK 只能在一个事务处理内使用(执行一条START TRANSACTION 命令之后)。
- 事务管理用来管理INSERT、UPDATE和DELETE语句。
- 不能回退SELECT语句、CREATE和DROP操作。
26.2.2 使用COMMIT
- 一般的MySQL语句都是隐含提交的,即提交(写或保存)操作都是自动的。
- 但事务处理块中,提交不会隐含地进行,使用COMMIT语句进行明确的提交。
1 | # 使用COMMIT语句仅在不出错时写出更改 |
- 当COMMIT或ROLLBACK语句执行后,事务会自动关闭(将来的更改会隐含提交)。
26.2.3 使用保留点
- 复杂的事务处理可能需要部分提交或回退。
为了支持回退部分事务处理,必须能在事务处理块中合适位置放置占位符,如果需要回退,可以回退到某个占位符。
创建占位符,使用SAVEPOINT,例如
SAVEPOINT delete1;
。- 每个保留点都标识它的唯一名字。
回退到保留点,
ROLLBACK TO delete1;
。保留点越多越好,越灵活。
- 保留点在事务处理完成后自动释放,也可以用RELEASE SAVEPOINT明确地释放保留点。
26.2.4 更改默认的提交行为
- MySQL默认自动提交所有更改。
- 为只是MySQL不自动提交更改,使用
SET autocommit=0;
。
第27章 全球化和本地化
27.1 字符集和校对顺序
- MySQL需要适应不同的字符集,适应不同的排序和检索数据的方法。
- 字符集:字母和符号的结合。
- 编码:某个字符集成员的内部表示。
- 校对:规定字符如何比较的指令。
- 使用何种字符集合校对的决定在服务器、数据库和表级进行。
27.2 使用字符集和校对顺序
- 查看所支持的字符集完整列表,
SHOW CHARACTER SET;
。 - 查看所支持校对的完整列表,
SHOW COLLATION
。 可以在安装时定义一个默认的字符集和校对,也可以在创建数据库时,指定默认的字符集和校对。为了确定所用的字符集和校对,使用语句,
SHOW VARIABLES LIKE 'character%'
和SHOW VARIABLES LIKE 'collation%'
。给表指定字符集和校对,使用带子句的CREATE TABLE。
1 | CREATE TABLE mytable |
- 除了可以给表指定字符集和校对,还可以对每个列设置它们。
1 | CREATE TABLE mytable |
- 校对在用ORDER BY子句检索出来的数据排序时起重要的作用。
1 | # 使用与创建表时不同的校对顺序排序特定的SELECT语句 |
第28章 安全管理
28.1访问控制
- 安全基础:用户应该对他们需要的数据具有恰当的访问权,既不能多也不能少。用户不能对过多的数据具有过多的访问权。
- 访问控制:给用户提供他们所需的访问权,且仅提供他们所需的访问权。
- 不要在日常操作中使用root。
28.2 管理用户
- 获取所有用户账户列表。
1 | # mysql数据库有一个名为user的表,它包含所有用户账号 |
28.2.1 创建用户账户
- 创建新用户。
1 | # 创建一个新用户,用户名ben,口令p@$$word |
- IDENTIFIED BY为纯文本口令,为了作为散列指定加密口令,使用IDENTIFIED BY PASSWORD。
- 重命名用户名。使用
RENAME USER ben TO bforta;
。
28.2.2 删除用户账户
- 使用DROP USER语句,如
DROP USER bforta;
。
28.2.3 设置访问权限
- 新创建的用户没有访问权限。
查看赋予用户的权限,
SHOW GRANTS FOR bforta;
。用户定义为user@host。默认主机名为%。
- 为设置权限,使用GRANT语句,需给出以下信息:
- 要授予的权限。
- 被授予访问权限的数据库或表。
- 用户名。
1 | # 允许用户在crashcourse.*(crashcourse数据库的所有表)上使用SELECT |
撤销特定的全效,使用REVOKE语句。
REVOKE SELECT ON crashcourse.* FROM bforta;
,撤销了bforta的SELECT访问权限。GRANT 和REVOKE可在几个层次上控制访问权限。
- 整个服务器,使用GRANT ALL 和 REVOKE ALL。
- 整个数据库,使用ON database.*。
- 特定的表,使用ON database.table。
- 特定的列。
- 特定的存储过程。
28.2.4 更改口令
- 使用SET PASSWORD,新口令必须使用Password加密:
SET PASSWORD FOR bforta = Password('n3w p@$$word')
。 - 设置自己的口令:
SET PASSWORD = Password('n3w p@$$word')
。
第29章 数据库维护
29.1 备份数据
- 使用命令行实用程序mysqldump转储所有数据库内容到某个外部文件。
- 可用命令行实用程序mysqlhotcopy从一个数据库复制所有数据。
- 可以使用MySQL的BACKUP TABLE或SELECT INTO OUTFILE转储所有数据到某个外部文件。
29.2 进行数据库维护
- ANALYZE TABLE,用来检查表键是否正确。
- CHECK TABLE,用来针对许多问题对表进行检查。
29.3 诊断启动问题
- 服务器启动问题通常在对MySQL匹配或服务器本身进行更改时出现。
- 排除系统启动问题时,首先应该尽量用手动启动服务器。
- mysql命令行选项。
- —help显示帮助。
- —safe -mode装载减去某些最佳配置的服务器。
- —verbose显示全文本信息。
- —version显示版本信息。
29.4 查看日志文件
- 错误日志。—log-error
- 查询日志。—log
- 二进制日志。—log- bin
- 缓慢查询日志。—log-slow-queries
第30章 改善性能
30.1 改善性能
- 运行在专用服务器上。
- 调整内存分配、缓冲区大小。
- 显示所有活动进程,KILL命令终结某个特定的进程。
- 使用联结、并、子查询等方法编写SELECT语句。
- 使用存储过程。
- 使用正确的数据类型。
- 不要检索比需求还要多的数据,尽量不要用SELECT *。
- 使用DELAYED关键字。
- 导入数据时,应该关闭自动提交。
- 索引数据库表以改善数据检索的性能。
- 使用多条SELECT语句和联结它们的UNION语句来替代一系列复杂的OR语句。
- LIKE很慢,最好使用FULLTEXT。
- 每条规则在某些条件下都会被打破。