数据库专家第一步
第1章:了解 SQL
1. 什么是数据库?
数据库是一个以某种有组织的方式存储的数据集合。(文件柜)
或者说是保存有组织的数据的容器。
我们常常使用 DBMS(数据库管理系统软件) 来操作数据库!
- 表: 某种特定类型数据的结构化清单。(单一数据库中唯一可标识)
- 列和数据结构:列是表中的一个字段,所有表都是由一个或多个列组成的
- 行:表中的数据是按行存储的,一行是一个数据库表中的一条记录。
- 主键:一列(一组列),其值能够唯一区分表中每一个行,也可以说是表示一个特定的 行。
列作为主键的条件(规则为MYSQL本身强制实施的):
- 任意两行都不具有相同的主键值
- 每个行都必须具有主键值(不为NULL)
应该总是定义主键:要保证每个表都有一个主键,以便于以后的数据操纵与管理
主键的最好习惯:
- 不更新主键列中的值
- 不重用主键列的值;
- 不在主键列中使用可能会更改的值
2. 什么是SQL?
结构化查询语言(Structured Query Language), SQL是专门与数据库通信的语言。
有以下优点:
- 通用性,学习此语言几乎能和所有数据库进行打交道。
- 简单易学,它的语句全是由描述性很强的英文单词组成,且这些单词数目不多。
- 实用性很强,虽简单,但灵活使用该语言能进行十分复杂和高级的数据库操作。
第2章:MySQL 简介
1. 什么是MySQL
MySQL 是一种 DMBS, 数据库软件。
客户-服务器软件:
客户端用于用户进行操作,并提交请求给服务器软件,服务器软件进行过滤,丢弃和排序数据再把结果返回到客户端软件中。
一般情况下,数据库客户和服务器软件安装在一台或不同的多台计算机上。
- 服务器软件为MySQL DBMS, 可以在本地安装的副本上运作,也可以连接在你具有访问权的远程服务器上的一个副本。
- 客户机可以是 MySQL 提供的工具, 脚本语言,程序设计语言开发
MySQL DMBS 版本
本书将介绍 MySQL 5
2. MySQL 工具
下面我们会用客户机工具来与 MySQL 打交道
mysql 命令行实用程序
在本地安装后我们要输入以下命令去登录到内部:
登录时要使用 用户名,主机名,端口和口令
mysql -u username -p -h hostname -P hostpassword
完整的命令行选项和参数列表可用 mysql --help 获得
mysql 命令行程序是使用最多的程序之一,对于快速测试和执行脚本非常有价值。
请注意:
- 命令输入在 mysql> 之后;
- 命令用 ; 或者 \g 结束,换句话说,仅按 Enter 并不会执行命令
- 输入 help 或者 \h 获取帮助,也可以输入更多的文本获取特定命令的帮助(如,输入 help select 获得
使用 SELECT 语句的帮助) - 输入 quit 或 exit 退出命令行实用程序;
建议: 熟悉mysql命令行实用程序,因为这是唯一你可以安全依靠的捆绑安装的客户机
第3章:使用MySQL
本章将会学习如何连接和登录到 MySQL,如何执行MySQL 语句,以及如何获取到数据库和表的信息。
1. 选择数据库
使用 USE 关键字来选择数据库;
2. 查看数据库和表
使用 SHOW 关键字 ,后跟 DATABASES(查看数据库) 和 TABLES (查看当前选择的数据库的可用表)
SHOW 也可以用来显示表的列结构 (SHOW COLUMNS FROM table_name),等同于 (DESCRIBE table_name)
他对每个字段都返回一行, 【行中包含字段名,数据类型,是否NULL,键信息,默认值以及其他信息】
其他常用SHOW语句:
- SHOW STATUS, 用于显示广泛的服务器状态信息
- SHOW CREATE DATABASE 和 SHOW CREATE TABLE, 分别用于显示创建特定数据库或表的 MySQL 语句
- SHOW GRANTS, 用来显示授予用户(所有用户或特定用户)的安全权限
- SHOW ERRORS 和 SHOW WARNINGS 用来显示服务器错误或警告信息。
第4章:检索数据
本章将介绍如何使用 SELECT 语句从表中检索一个或多个数据列。
1. SELECT 语句
目前来说,最经常使用的 SQL 语句就是 SELECT 语句了,用途是从一个或多个表中检索信息。
为了使用 SELECT 检索表数据,需要给出两条信息: 找什么? 从什么地方找?
2. 检索单个列
命令: SELECT column_name FROM table_name;
注意: 如果没有明确排序查找结果,则返回的数据的顺序没有特殊意义(有可能是数据被添加到表中的顺序,也可能不是,只要返回相同数目的行,就是正常的)
3. 检索多个列
以列名分隔开即可,最后一个列不加 逗号
SELECT column1, column2, column3 FROM table_name;
4. 检索所有列
使用通配符 * 来返回表中所有列, 列的顺序一般是在表定义中出现的顺序,表的模式的变化(添加或删除列)可能会导致顺序的变化。
使用通配符: 一般,除非确实需要每个列才使用通配符 *,其他情况使用会降低检索和应用程序的性能。
SELECT * FROM table_name;
5. 检索不同的行
检索出有不同值的列表 : DISTINCT 关键字
SELECT DISTINCT column_name FROM table_name;
注意: 不能部分使用DISTINCT 仅应用于所有列而不仅仅是前置它的列, 除非指定的两个列都相同,否则所有行都会被检索出来。
6. 限制结果
限制最终结果的显示行数可使用: LIMIT
SELECT column1 FROM table_name LIMIT [start_line,] get_line_count
指定结果的开始行,和行数(指定行数后,是不包括开始行开始计数的), 行数不够时显示所有行
上语句在 MySQL5 等价于:
LIMIT get_line_count offset start_line
7. 使用完全限定的表名
SELECT table_name.column FROM table_name;
SELECT table_name.column FROM databse.table_name
第5章:排序检索数据
本章将讲授如何使用 SELECT 语句的 ORDER BY 子句, 根据需要排序检索出的数据。
1. 排序数据
如果不明确规定排序顺序,则不应该假定检索出的数据的顺序有意义。
子句: SQL 语句由子句构成,有些子句是必需,有些是可选的。一个子句通常由一个关键字和所提供的数据组成。
例如:SELECT 语句的 FROM子句。
为了明确地排序 SELECT 语句检索出的数据,可使用 ORDER BY 子句,ORDER BY 子句取一个或多个列的名字,据此对输出进行排序。
SELECT column_name FROM table_name ORDER BY column_name;
通过非选择列进行排序是完全合法的,上图最后一个语句即是演示
2. 按多个列排序
规则是:比较第一列,如果第一列不能比出顺序,则第二列。。。。。
SELECT column1, column2 FROM table_name ORDER BY column1, column2
3. 指定排序方向
默认排序为 ASC (ASCENDING) 升序
DESC(降序)
SELECT column1, column2 FROM table_name ORDER BY column1 DESC;
DESC 关键字只作用于位于其前面的列名。
第6章: 过滤数据
本章将讲授如何使用SELECT语句中的 WHERE 子句指定搜索条件
1. 使用 WHERE 子句
在SELECT语句中,数据根据 WHERE 子句指定的搜索条件进行过滤,WHERE子句在表名(FROM子句之后给出)
SELECT column1 FROM table_name WHERE condition
WHERE 子句的位置: 在同时使用 ORDER BY 和 WHERE 子句时,应该让 ORDER BY 位于 WHERE 之后,否则错误。
2. WHERE 子句操作符
WHERE 子句的条件判定,可以使用如下 MySQL 支持的所有条件操作符
操作符 | 说明 |
---|---|
= | 等于 |
<> | 不等于 |
!= | 不等于 |
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
BETWEEN | 在指定的两个值之间 |
注意: MySQL 执行匹配时默认不区分大小写 (字符串),且字符串值需要加 ‘’
例子1:检测单个值
例子2:不匹配检测
例子3:范围值检测
使用 BETWEEN 操作符可以在 条件中给定 两个值表示一个区间,去检测。
SELECT column1 FROM table_name WHERE column BEWEEM startvalue AND endvalue
4. 空值检测
不包含任何值时,称为包含空值 NULL;
NULL 无值,与字段包含 0, 空字符串和仅仅包含空格不同。
SELECT 语句使用特殊的WHERE 子句来检测 NULL 值的列。 这个 WHERE 子句就是 IS NULL 子句。
SELECT column1 FROM table_name WHERE column IS NULL;
注意: 在过滤选择不具有特定值的行时, 数据库并不会认为 NULL 与 他们匹配,因此在(不)匹配过滤中不会返回他们。
第7章:数据过滤
本章介绍如何组合 WHERE 子句以简历功能更强更高级的搜索条件,我们还将学习 NOT 和 IN 操作符
1. 组合 WHERE 子句
为了更强的过滤控制, MySQL 允许给出多个 WHERE 子句。这些子句可以两种方式使用: 以 AND 子句的方式或OR子句的方式使用。
操作符: 用来联结或改变 WHERE 子句中的子句的关键字, 也成为逻辑操作符。
1. AND 操作符
为了通过不止一个列进行过滤, 可以使用 AND 操作符给 WHERE 子句附加条件,并且可以添加多个过滤条件, 每添加一条就要使用一个 AND
SELECT cloumn1 FROM table_name WHERE condition1 AND condition2;
2. OR 操作符
OR 匹配任意条件 进行过滤, 若符合给出 WHERE 子句中的任一条件都会被筛选出来。
SELECT column1 FROM table_name WHERE condition1 OR condition2;
3. 计算次序
SQL 语句中 OR 操作符的优先级低于 AND 操作符,当然可以使用圆括号进行明确分组。
建议: 在 WHERE 子句中要使用圆括号明确地分组操作符,可以消除歧义,这样是最直接好阅读的。
2. IN 操作符
IN 操作符用来指定条件范围,范围内的每个条件都可以进行匹配。
IN 取合法值的由逗号分割的清单,全都括在圆括号中。
SELECT column1 FROM table_name WHERE column IN(val,val)
IN 作用和 OR 类似:
但使用 IN 的优点如下:
- 在使用长的合法选项清单时, IN 操作符的语法更清楚直观
- 在使用 IN, 计算的次序更容易管理
- IN 操作符一般比 OR 执行更快
- IN 的最大优点是可以包含其他 SELECT 语句,使得其能够更动态地建立 WHERE 子句。
3. NOT 操作符
NOT 操作符的功能: 否定它之后所跟的任何条件。
SELECT column1, column2 FROM table_name WHERE column NOT condition
第8章:使用通配符进行过滤
本章将介绍什么是通配符,以及如何使用通配符以及怎样使用 LIKE 操作符进行通配搜索,以便对数据进行复杂过滤。
1. LIKE 操作符
通配符: 用来匹配值的一部分的特殊字符
搜索模式: 由字面值,通配符或两者组合构成的搜索条件。
通配符本身实际是 SQL 的 WHERE 子句中有特殊含义的字符, SQL 支持几种通配符。
为了在搜索子句中使用通配符,必须使用 LIKE 操作符。 LIKE 指示 MySQL,后跟的搜索模式利用通配符匹配而不是直接相等匹配进行比较。
1. 百分号(%)通配符
% 表示任何字符出现任意次数。
SELECT column1 FROM table_name WHERE column LIKE 'hand%';
% 通配符可以放置在 搜索模式的 任意位置,并匹配 给定位置的 0个,1个,多个字符。
注意: 空格会影响匹配,例如 ’anvil ‘ 与 ‘%anvil’ 就匹配不上。
% 似乎可以匹配任何东西,但 ‘%’ 是匹配不上 NULL 的行的
2. 下划线(_) 通配符
与%类似, _ 通配符能匹配任意字符, 但只能匹配一个字符,不能多也不能少
SELECT column1 FROM table_name WHERE column LIKE '_'
2. 使用通配符的技巧
MySQL 的通配符是很有用的,但这种功能是有代价的: 通配符的搜索处理相比普通搜索要更慢一点。
使用通配符的技巧:
- 不要过度使用通配符, 如果其他操作符能达到相同目的, 应该使用其他操作符
- 在确实需要使用通配符时, 除非绝对有必要,否则不要让他们用在搜索模式的开始处。把通配符置于搜索模式的开始处, 搜索起来是最慢的。
- 仔细注意通配符的位置,如果放错地方,可能不会返回想要的数据。
第9章: 用正则表达式进行搜索
本章将学习如何在 MySQL WHERE 子句中内使用 正则表达式来更好的控制数据过滤。
1. 正则表达式介绍
随着过滤条件的复杂度增加, WHERE 子句的复杂性也有必要增加
这就是正则表达式有用的地方, 正则表达式是用来匹配文本的特殊的串(字符集合)
正则表达式用正则表达式语言来建立, 有必须学习的特殊语法和指令 😭 又要背东西,呜呼!!!
注意: 这里只会介绍正则表达式的基本知识, 其他完全介绍请参考其他书籍。
2. 使用 MySQL 正则表达式
MySQL 用 WHERE 子句对正则表达式提供了初步的支持,允许你指定正则表达式来过滤 SELECT 检索的数据。
注意: MySQL 仅支持多数正则表达式实现的一个很小的子集。
1. 基本字符匹配 (REGEXP)
SELECT column1 FROM table_name WHERE column REGEXP '匹配表达式';
这里 : . 是匹配单个任意字符
这里正则表达式匹配的结果是 ssssssss, 因为 . 这个字符会限定 ‘.ssss’ 匹配模式串中 ssss 至少要有一个 字符,这样就能过滤到一部分。
正则表达式是一种匹配子串的过程,所以若整串中有符合匹配模式的字串就会被筛选出。
LIKE 与 REGEXP:
正则表达式是一种匹配子串的过程,所以若整串中有符合匹配模式的字串就会被筛选出。, 而 LIKE 可以说是匹配整串的过程。
2. 进行 OR 匹配
正则表达式进行 OR 匹配的操作是使用 | 来划分
SELECT column1 FROM table_name WHERE column REGEXP 'value1|value2';
多个值即: ‘value1|value2|value3’
3. 匹配几个字符之一
匹配任意单一字符,但你想匹配特定的字符,可以使用 [ ] , 来替换 OR 作为另一种形式。
SELECT column1 FROM table_name WHERE column REGEXP '[valuevalue]1111';
[] 与 | 的区别是, | 并不能很好的区分匹配规则, [ ] 会限定死这个位置上的特定字符。,看如下例子
其他应用: 字符集也可以使用 ^ 进行否定,来匹配这些字符外的其他东西。
SELECT column1 FROM table_name WHERE column REGEXP '[^valuevalue]';
4. 匹配范围
为了简化 类似 [0123456789] ,我们可以使用 - 来定义一个范围 [0-9]
[a-z] 也意味着匹配任意字母字符
SELECT column1 FROM table_name WHERE column REGEXP '[a-z]'
5. 匹配特殊字符
在使用特殊字符进行制作正则表达式语句时,需要加上 ‘\\’ 作为前导 , ‘\\-’ 表示查找 -
SELECT column1 FROM table_name WHERE column REGEXP '\\-';
这种处理也可以说是转义, 正则表达式内具有特殊意义的所有字符都必须以这种方式转 义。
元字符 | 说明 |
---|---|
\\f | 换页 |
\\n | 换行 |
\\r | 回车 |
\\t | 制表 |
\\v | 纵向制表 |
注意: 如果为了匹配 反斜杠 \ 自身,使用 \\
注意: 多数正则表达式实现单个反斜杠转义特殊字符, 以便能使用这些字符本身,但 MySQL 使用两个反斜杠(MySQL 自己解释一个, 正则表达式库解释另一个)
6. 匹配字符类
存在找出你自己经常使用的数字, 所有字母字符或所有数字字母字符等的匹配, 为了更方便工作,可以使用预定义的字符集,称为字符类
下面列出字符类以及它们的含义。
类 | 说明 |
---|---|
[:alnum:] | 任意字母和数字 (同[a-zA-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]) |
[:xdight:] | 任意十六进制数字 (同[a-fA-F0-9]) |
7. 匹配多个实例
单个匹配的功能有时候不能被满足需求,需要使用 更强大的 匹配重复 功能。
正则表达式用重复元字符来完成匹配多个实例。
元字符 | 说明 |
---|---|
* | 0个或多个匹配 |
+ | 1个或多个匹配 {1,} |
? | 0个或1个匹配 {0,1} |
{n} | 指定数目的匹配 |
{n,} | 不少于指定数目的匹配 |
{n, m} | 匹配数目的范围 (m 不超过 255) |
8. 定位符
这里我们来介绍如何匹配 特定位置的文本,如下列出的定位符
元字符 | 说明 |
---|---|
^ | 文本的开始 |
$ | 文本的结尾 |
[[:<:]] | 词的开始 |
[[:>:]] | 词的结尾 |
SELECT '1.2' REGEXP '[0-9\\.]'
我们来筛选用户名 以 不低于 4个s字符开头的,或 得字开头的用户:
注意:
- ^ 的双重用途: ^ 有两种用法,在集合中(用 [和]定义),用它来否定该集合,否则用来指串的开始处。
- 使得 REGEXP 起类似 LIKE 的作用: 使用 ^ 开始每个表达式, $ 结束
简单的正则表达式测试:
可以在不使用数据库表的情况下用 SELECT 来测试正则表达式, REGEXP 检查总是返回 0 (没有匹配) 或 1(匹配) 。可以用带文本串的 REGEXP 来测试表达式, 并试验他们。 响应的语法如下:
SELECT ‘hello’ REGEXP ‘[0-9]’;
第10章: 创建计算字段
本章将介绍什么是计算字段, 如何创建计算字段以及怎样从应用程序中使用别名进行引用他们。
1. 计算字段
存储在数据库表中的数据一般不是 客户端 所需要的格式,虽然我们可以直接取出数据发给客户端由客户端进行加工,但是在数据库服务器上完成这些操作比在客户端机中要快得多, 因为 DBMS 是设计来快速有效地完成这种处理的。
这时对数据进行加工处理便是计算字段发挥作用的所在了。
字段: 基本上与列的意思相同, 经常互换使用,不过数据库列一般称为列,而术语字段通常用在计算字段的连接上。
2. 拼接字段
拼接: 将值连接到一起构成单个值
在SELECT 语句中,可以使用 Concat() 函数来拼接两个列。(多数 DBMS 使用 + )
SELECT Concat(column1, column2, val,val...) FROM table_name;
去除空格: 取出字符串左右的空格。
Trim() : 去除值左右两边的空格。
LTrim() : 取出值左边的所有空格。
RTrim(): 取出值右边的所有空格。
使用别名
上图我们可以看到,拼接后或者经过计算字段处理后 会生成新的计算列,但无名字,一个未命名的列不能用于客户机应用中,因为客户机没有办法引用它。
为了解决这个问题,SQL 支持列别名,别名仅仅是一个字段或值的替换名。 别名用 AS 关键字赋予,请看下面的 SELECT 语句:
SELECT CONCAT(TRIM(column1), column2, column3...) AS new_column FROM table_name;
之后就可以按照名引用到这个列进行使用。
3. 执行算术计算
可以在列之间使用 算术运算符来 获取执行算术运算后的结果
SELECT column1, column2, column1 [* - + /] column2 AS result_column FROM table_name;
如何测试计算: SELECT 提供了测试和试验函数与计算的一个很好的办法。
省略 FROM 子句以便简单访问和处理表达式:
第11章: 使用数据处理函数
本章介绍什么是函数, MySQL 支持何种函数,以及如何使用这些函数。
1. 函数
SQL 支持使用函数来处理数据, 函数一般是在数据上执行的,它给数据的转换和处理提供了方便。
注意: 函数没有 SQL 的可移植性强
多数的 SQL 语句是可移植的, 在 SQL 实现之间有差异时,这些差异通常不那么难处理,而函数的可移植性却不强。 几乎每种主要的 DBMS 的实现都支持其他实现不支持的函数,而且有时候差异还很大。
如果使用比较通用性的函数,移植性较高,但可能导致效率低下, 因此如果决定使用该函数, 应该注意保证做好代码注释,以便以后你能确切地知道所编写 SQL 代码的含义。
2. 使用函数
大多数 SQL 实现支持以下类型的函数。
- 用于处理文本串(如删除或填充值, 转换值为大写或小写)的文本函数。
- 用于在数值数据上进行算是操作(如返回绝对值, 进行代数运算)的数值函数。
- 用于处理日期和时间值并从这些值中提取特定成分(例如,返回两个日期之差,检查日期有效性等)的日期和时间函数。
- 返回 DBMS 正使用的特殊信息(如返回用户登录信息,检查版本细节)的系统函数。
1. 文本处理函数
常用的文本处理函数
函数 | 说明 |
---|---|
Left() | 返回串左边的字符 |
Length() | 返回串的长度 |
Locate() | 找出串的一个字串 |
Lower() | 将串转换为小写 |
LTrim() | 去掉串旁边的空格 |
Right() | 返回串右边的字符 |
RTrim() | 去掉串右边的空格 |
Soundex() | 返回串的 SOUNDEX 值 |
SubString() | 返回字串的字符 |
Upper() | 将串转换为大写 |
示例:
Upper()
SELECT Upper(column1) FROM table_name;
SOUNDEX() : 能对串进行发音比较而不是字母比较
SELECT column1 FROM table_name WHERE SOUNDEX(column) = '发音'
2. 日期与时间处理函数
日期和时间采用相应的数据累心和特殊的格式进行存储,以便能快速和有效的进行排序过滤,节省物理存储空间。
一般来说,应用程序并不使用存储日期和时间的格式, 因此日期和时间函数总是被用来读取,统计和处理这些值 。由于这个原因,日期和时间函数在 MySQL 函数中有重要的作用。
函数 | 说明 |
---|---|
AddDate() | 增加一个日期(天,周) |
AddTime() | 增加一个时间(时,分) |
CurDate() | 返回当前日期 |
CurTime() | 返回当前时间 |
Date() | 返回日期时间的日期部分 |
DateDiff() | 计算两个日期之差(天,周) |
Date_Add() | 高度灵活的日期计算函数 |
Date_Format() | 返回一个格式化的日期或时间串 |
Day() | 返回一个日期的天数部分(天,周) |
DayOfWeek() | 对于一个日期,返回对应的星期几(天,周) |
Hour() | 返回一个时间的小时部分 |
Minute() | 返回一个日期的分钟部分 |
Month() | 返回一个日期的月份部分 |
Now() | 返回当前日期和时间 |
Second() | 返回一个时间的秒部分 |
Time() | 返回一个日期时间的时间部分 |
Year() | 返回一个日期的年份部分 |
接下来我们讲一下使用WHERE 进行过滤 时间数据时的注意点:
- 日期格式必须为 yyyy-mm-dd ,这样能消除二义性,因为 SQL 在处理 70-99 为 1970-1999,应该总是使用4位数字的年份
- 如果要的是日期,请使用 Date() 进行过滤掉时间部分。
如果你要的是 2020-03-21 日的信息,但 datatime 会记录日期和时间,如果这样匹配是不合理的,使用 Date 取 3-21 的部分即可。
这里我们写一个例子: 检索2005年9月下的所有订单?
SELECT cust_id FROM orders WHERE DATA(order_date) BETWEEN '2005-09-01' AND '2005-09-30';
SELECT cust_id FROM orders WHERE YEAR(order_date) = 2005 AND MONTH(order_date) = 9;
3. 数据处理函数
数据处理函数 在 DBMS 中是比较统一的。
函数 | 说明 |
---|---|
Abs() | 返回一个数的绝对值 |
Cos() | 返回一个角度的余弦 |
Exp() | 返回一个数的指数值 |
Mod() | 返回除操作的余数 |
Pi() | 返回圆周率 |
Rand() | 返回一个随机数 |
Sin() | 返回一个角度的正弦 |
Sqrt() | 返回一个数的平方根 |
Tan() | 返回一个角度的正切 |
第12章: 汇总数据
本章介绍什么是 SQL 的聚集函数以及如何利用它们汇总表的数据。
1. 聚集函数
对于仅需要汇总数据而不必检索出数据条目的需求, MySQL 提供了专门的函数,使用这些函数, MySQL 查询可用于检索数据, 以便分析和报表生成,例如:
- 确定表的行数(符合条件的条有多少)
- 获得表中行组的和
- 找出表列(或所有行或某些特定的行)的最大值,最小值和平均值
返回实际表数据对时间和资源都是浪费,因此 使用 聚集函数就是最优解。
聚集函数: 运行在行组上,计算和返回单个值的函数。
函数 | 说明 |
---|---|
AVG() | 返回某列的平均值 |
COUNT() | 返回某列的行数 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
SUM() | 返回某列值之和 |
扩展:
标准偏差: MySQL 还支持一系列的标准偏差聚集函数。
1. AVG() 函数
作用: 通过对表中行数计数并计算特定列值之和,求得该列的平均值。
注意:
- AVG 只能用于确定特定数值列的平均值,而且列名必须作为函数参数给出。
- NULL 值 AVG 函数忽略列值为 NULL 的行。
2. COUNT() 函数
作用: 进行计数,可利用COUNT () 确定表中行的数目或符合特定条件的行的数目。
COUNT() 函数有两种计数方式:
- 使用 COUNT(*) 对表中行的数目进行计数, 不管表中包含的空值(NULL) 还是非空值。
- 使用 COUNT(column) 对特定列中具有值的行进行计数, 忽略 NULL 值。
3. MAX() 函数
MAX() 返回指定列中的最大值。 MAX() 要求指定列名
注意:
- 对非数值数据使用 MAX() : 虽然 MAX() 一般用来找出最大的数或日期值, 但 MySQL 允许将它用来返回任意列的最大值,包括返回文本列中的最大值, 在用于文本数据时,如果数据按对应的列排序,则MAX返回最后一行。
- NULL: MAX() 忽略列为 NULL 的值。
4. MIN() 函数
与 MAX 相反
5. SUM() 函数
作用: 返回指定列值的和(总计)
SELECT SUM(column1) FROM table_name WHERE column = val;
SUM 也能对多个列进行计算统计:
SELECT SUM(OPERATOR(column1, column2)) AS new_oper_column FROM table_name WHERE column = val;
NULL值: SUM() 函数忽略列值为 NULL 的行。
2. 聚集不同值
下面我们会介绍聚集函数的 DISTINCT 的使用,已经被添加到 MySQL 5 中。
以上五个聚集函数都可以如下使用:
- 对所有的行执行计算,指定 ALL 参数或不给参数 (因为ALL是默认行为)
- 只包含不同的值,指定 DISTINCT 参数, DISTINCT 必须指定列名。
注意: ALL 参数不需要指定,因为它是默认行为, 如果不指定 DISTINCT,则假定为 ALL。
SELECT AVG(DISTINCT column1) AS avg_price FROM table_name WHERE condition;
注意:
- DISTINCT 不能用于 COUNT(*), 只能用于指定行的 COUNT(column)
- 可以使用 DISTINCT 用于 MAX() 与 MIN() , 但没什么用。
3. 组合聚集函数
其实SELECT 语句可根据需要包含多个聚集函数。
SELECT COUNT(*) AS num_items, MIN(price) AS price_min, MAX(price) AS price_max FROM table_name;
第13章: 分组数据
本章将介绍如何分组数据, 以便能汇总表内容的子集。这涉及两个新 SELECT 语句子句, 分别是 GROUP BY 子句和 HAVING 子句。
1. 数据分组
目前为止的所有计算都是在表的所有数据或匹配特定的 WHERE 子句的数据上进行的。
例如: 返回 一个 玩家id 为 1003 的拥有商品
SELECT COUNT(item) AS count_Item FROM item_table WHERE player_id = 1003;
但如果要返回每个玩家的拥有商品数目怎么办?
或者返回 10 个玩家所拥有的商品?
这样的需求,需要使用分组操作,分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。
2. 创建分组
分组是在 SELECT 语句总的 GROUP BY 子句中进行建立的。
这里上述例子演示分组:
SELECT COUNT(item) AS count_item FROM item_table GROUP BY player_id;
这样就能取出 每个玩家的拥有商品数量
在具体使用GROUP BY 子句前, 需要知道一些重要的规定。
- GROUP BY 子句可以包含任意数目的列, 这使得能对分组进行嵌套,为数据分组提供更细致的控制。
- 如果在 GROUP BY 子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(并不能从个别的列取回数据)
- GROUP BY 子句中列出的每个列都必须是检索列或有效的表达式(不能是聚集函数)。 如果在 SELECT 中使用表达式,则必须在 GROUP BY 子句中指定相同的表达式。不能使用别名。
- 除了聚集计算语句外, SELECT 语句中每个列都必须在 GROUP BY 的子句中给出。
- 如果分组列中具有 NULL 值, 则 NULL 作为一个分组返回。 如果列中多个NULL,他们将被分为一组。
- GROUP BY 子句必须出现在 WHERE 子句之后, ORDER BY 子句之前。
使用 ROLLUP: 使用 WITH ROLLUP 关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组)的值,如下所示:
SELECT COUNT(column1) AS count_item FROM table_name GROUP BY column WITH ROLLUP;
3. 过滤分组
WHERE 过滤的是行,但如果我们想过滤分组,我们应该使用 HAVING 子句。
HAVING 支持所有 WHERE 操作符:他们的语法是相同的,只是关键字有差别。
SELECT column1, (COUNT*) FROM table_name GROUP BY column1 HAVING condition;
HAVING 和 WHERE 的区别:
WHERE 在分组前进行过滤, HAVING 在分组后进行过滤。因此使用 WHERE 子句过滤掉不符合的列,之后进行分组再通过 GROUP BY 进行过滤分组。
4. 分组和排序
GROUP BY 和 ORDER BY 经常完成相同的工作,但实际上他们是非常不同的。
ORDER BY | GROUP BY |
---|---|
排序产生的输出 | 分组行, 但输出可能不是分组的顺序 |
任意列都可以(非选择的列也能使用) | 只可能使用选择列或表达式列, 而且必须使用每个选择列表达式 |
不一定需要 | 如果与聚集函数一起使用列(表达式),则必须使用 |
不要忘记 ORDER BY:
一般在使用 GROUP BY 子句时,应该也给出 ORDER BY 子句。这是保证数据正确排序的唯一方法。千万不要依赖 GROUP BY 子句
SELECT column1, SUM(column2 * column3) AS ordertotal FROM table_name
GROUP BY column1 HAVING SUM(column2 * column3) conditon ORDER BY ordertotal;
5. SELECT 子句顺序
SELECT 子句及其顺序
子句 | 说明 | 是否必须使用 |
---|---|---|
SELECT | 要返回的列或表达式 | 是 |
FROM | 从中检索数据的表 | 仅在从表选择数据时使用 |
WHERE | 行级过滤 | 否 |
GROUP BY | 分组说明 | 仅在按组计算聚集时使用 |
HAVING | 组级过滤 | 否 |
ORDER BY | 输出排序顺序 | 否 |
LIMIT | 要检索的行数 | 否 |
第14章: 使用子查询
本章介绍什么是子查询以及如何使用它们。
1. 子查询
子查询: 嵌套在其他查询中的查询。
2. 利用子查询进行过滤
这里我们有一个 user 表存储账户信息, id, username,password ,之后 result 存放战绩, id, userid, wincount, totalcount.
我们找到 wincount > 1 的 账号 username
SELECT username FROM user WHERE id in (SELECT userid FROM result WHERE wincount > 1);
格式化 SQL:
包含子查询的 SELECT 语句难以阅读和调试, 特别是它们较为复杂时更是如此。 如上所示把子查询分解为多行并且适当地进行缩进,能极大地简化子查询的使用。
注意:
- 子查询作为结果时应注意列的匹配
- 子查询的性能是堪忧的。
3. 作为计算字段使用子查询
这里我们有一个 user 表存储账户信息, id, username,password ,之后 result 存放战绩, id, userid, wincount, totalcount.
我们筛选出 username,password, wincount 这种规则的数据, 会想着将id带入子查询并取得 wincount,对这就是作为计算字段使用子查询。
SELECT username,password, (SELECT wincount FROM result WHERE result.userid = user.id)
AS wincount FROM user ORDER BY wincount;
涉及外部查询的子查询也叫相关子查询: 任何只要列明可能有多义性,就应该使用这种语法(表名和列名由一个句点分隔)。
总结建议:
逐渐增加子查询来建立查询:
- 用子查询测试和调试查询很有技巧性, 特别是在这些语句的复杂度不断增加的情况下更是如此。
- 用子查询建立(和测试)查询的最可靠的方法是逐渐进行,这与 MySQL 处理它们的方法非常相同。
首先: 建立和测试内层的查询。
然后: 用硬编码数据建立和测试外层查询,并且仅在确认它正常后才嵌入子查询。
这时:再次测试它,对于要增加的每个查询,重复这些步骤,这样仅仅给构造查询增加了一点点时间,但节省了之后对语句测试的大量时间,并且极大地提高了一开始就正常工作的可能性。
第15章: 联结表
本章将介绍什么是联结,为什么要使用 联结,如何编写使用联结的 SELECT 语句。
1. 联结
SQL 最强大的功能之一就是能在数据检索查询的执行中联结(join)表。
在能够有效地说明联结前,必须了解关系表以及关系数据库涉及的一些基础知识。
1. 关系表
一个表定义了主键, 且另一个表定义了外键,且之间相互对应,称为这两个表是关系表,且关系数据可以有效地存储和方便处理。
主键: 唯一标识一行数据的键。
外键: 包含另一个表的主键值的键。
关系表的好处可伸缩性:能够适应不断增加的工作量而不失败,设计良好的数据库或应用程序称之为 可伸缩性好。
2. 为什么要使用联结
分解数据为多个表能更有效地存储,更方便地 处理,并有更大的可伸缩性,这些好处是有代价的。
如果数据存储在多个表中,怎样用单条 SELECT 语句检索出数据?
利用联结可以使用单条 SELECT 语句检索出数据。
联结: 是一种机制,用来在一条 SELECT 语句中关联表, 因此称为联结。 使用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行(联结也仅存在于查询的执行当中)。
2. 创建联结
SELECT column1, column2 FROM table1,table2 WHERE table1.id = table2.table1_id;
1. WHERE 子句的重要性
在联结两个表时, 你实际上做的是将第一个表中的每一行与第二个表中的每一行配对。
WHERE 子句作为过滤条件,它只包含那么匹配给定条件的(这里是联结条件的)行。
2. 内部联结
上述演示的联结为等值联结,基于两个表的相等性测试。
等值联结的其他语法:(推荐使用)
SELECT column1, column2 FROM table1 INNER JOIN table2 ON table1.id = table2.table_id;
3. 联结多个表
SELECT column1, column2 FROM table1,table2,table3 WHERE table1.id = table2.table1_id AND
table2.id = table3.table2_id;
性能考虑: MySQL 在运行时关联指定的每个表以处理联结,这种处理可能是非常耗费资源的,因此应该仔细,不要联结不必要的表,联结的越多,性能下降越厉害。
第16章:创建高级联结
本章将讲解另外一些联结类型(包括它们的含义和使用方法)。介绍如何对被联结的表使用表别名和聚集函数。
1. 使用表别名
别名除了可以用于列名和计算字段外, SQL 还允许给表名起别名, 这样做的理由:
- 缩短 SQL 语句
- 允许在单条 SELECT 语句中多次使用相同的表。
缩短 SQL 语句的例子:
SELECT column1 FROM table_name1 AS t1, table_name2 AS t2 WHERE t1.cust_id = t2.cust_id;
应该注意: 表别名只在查询执行中使用, 与列别名不一样, 表别名不返回客户机。
2. 使用不同类型的联结
下面我们来讲解一下其他的三种联结: 自联结, 自然联结和外部联结。
1. 自联结
使用表别名的主要原因也是能在单条 SELECT 语句中不止一次引用相同的表。
自联结是在作为外部语句用来从相同表中检索数据。 相比子查询效率较高。
例如:
SELECT p1.id, p2.name FROM table AS p1, table AS p2 WHERE p1.id = p2.id AND p2.id = 'conditon';
假若有一个产品出问题了,我们要查询到产品所属 供货商的 id,并去检索供货商的所有产品:
2. 自然联结
无论何时对表进行联结,应该至少有一个列出现在不止一个表中(被联结的列, 外键与主键对应,所有至少这一个列重复)
自然联结是这样一种联结: 其中你只能选择那些唯一的列,这** 一般是通过对表使用通配符(SELECT *),对其他表的列使用明确的子集完成的。
事实上,我们建立的每个内部联结都是自然联结,很可能我们永远不会用到不是自然联结的内部联结。
3. 外部联结
许多联结会将一个表的行于另一个表中的行进行相关联, 但有适合会需要关联没有关联行的那些行:
例如:
- 对每个客户下了多数订单进行计数,包括那些至今尚未下订单的客户;
如果客户尚未下订单,这时在订单表中就无其对应记录, 但是也要进行关联,哪怕是空,这时在
联结中包含了那些在相关表中没有关联行的行。 这叫外部联结。
外联结的语法:
SELECT table1.info, tanle2.info FROM table1 LEFT/RIGHT OUTER JOIN table2 ON
connect_condition;
以左表为核心,使用左连接,以右边为核心,使用右脸接
注意:
- MySQL 没有 (*= 和 =**) 这两种使用
- 左连接和右联结的类型根据实际情况方便而定义。
3. 使用带聚集函数的联结
我们来介绍 如何 在联结中使用 聚集函数。
4. 使用联结 和 联结条件
汇总一下关于联结和使用的某些要点:
- 注意所使用的联结类型(内部联结, 外部联结)
- 保证使用正确的联结条件,否则将返回不正确的数据
- 应该总是提供联结条件,否则会得出笛卡儿积
-在一个联结中可以包含多个表, 甚至对于每个联结可以采用不同的联结类型,。虽然这样做是合法的,一般也很有效,但应该在一起测试它们前,分别测试每个联结,这将使故障排除更为简单。
第17章:组合查询
本章将介绍如何 利用 UNION 操作符将多条 SELECT 语句组合成一个结果集
1. 组合查询
MySQL 允许执行多个查询(多条 SELECT 语句),并将结果作为单个查询结果集返回。 这些组合查询通常称为 并 (union)或 复合查询。
有两种基本情况, 其中需要使用组合查询:
- 在单个查询中从不同的表返回类似结构的数据。
- 对单个表执行多个查询, 按单个查询返回数据。
组合查询和多个 WHERE 条件:
任何具有多个 WHERE 子句的 SELECT 语句都可以作为一个组合查询给出,这两种技术在不同的查询中性能也不同。
2. 创建组合查询
利用 UNION,可给出多条 SELECT 语句,并将它们的结果组合成单个结果集合。
1. 使用 UNION
UNION 的使用规则:
SELECT column FROM table WHERE conditon UNION SELECT column2 FROM table2 WHERE condition;
我们来写一个例子:
假如需要小于等于 5 的价格的所有物品的一个列表,并且还想包括供应商 1001 和 1002 生产的物品(不考虑物品)。
但是你可能发现: UNION 的使用有时没有 直接用 WHERE OR 更加简单。
2. UNION 规则
正如所见, UNION 是非常容易使用的,但在进行UNION 时有几条规则需要注意:
- UNION 必须由两条或两条以上的 SELECT 语句组成,语句之间用关键字 UNION 分割
- UNION 中的每个查询都必须包含相同的列,表达式或聚集函数(不过各个列不需要以相同的次序列出)
- 列数据结构必须兼容: 类型不必完全相同,但 必须是 DMBS 可以隐式地转换的类型(例如: 不同的数值类型或不同的日期类型)
3. 包含或取消重复的行
UNION 从查询结果集中自动去除了重复的行(即它的行为和 单条 SELECT 语句中使用 WHERE 子句条件一样)。
如果需要, 可以改变这种默认行为:可使用 UNION ALL 而不是 UNION, 同时 WHERE 也是完成不了这个工作的。