数据查询语言(DQL)

162 阅读29分钟

案例数据库说明

  • 数据库名为nsd2021,共有三张表

  • departments表:部门表,共有8个部门

字段类型说明
dept_idint(4)部门号
dept_namevarchar(20)部门名
  • employees表:员工表,共有133位员工,属于不同部门
字段类型说明
employee_idint员工号
namevarchar()姓名
birth_datedate生日
hire_datedate入职日期
phone_numberchar(11)电话号码
emailvarchar(30)email地址
dept_idint所在部门编号
  • salary表:工资表,记录自2015年以来的工资
字段类型说明
idint行号
datedate发工资日期
employee_idint员工编号
basicint基本工资
bonusint奖金
  • 三张表的关系:
    • 部门表departments与员工表employees之间有外键约束关系,employees表的的dept_id字段必须出现在departments表中
    • 员工表employees和工资表salary表之间有外键约束关系,salary表的employee_id必须出现在employees表中

ER.png

SQL语句基础

常用MySQL命令

# 查看所有数据库
mysql> SHOW DATABASES;
# 切换指定数据库
mysql> USE nsd2021;
# 查看当前库中所有的表
mysql> SHOW TABLES;
# 查看表结构
mysql> DESC departments;
# 查看当前所处的数据库
mysql> SELECT DATABASE();
# 查看当前登陆用户
mysql> SELECT USER();
# 查看版本
mysql> SELECT VERSION();
[root@localhost ~]# mysql --version
[root@localhost ~]# mysql -V

语法规范

  1. 不区分大小写,但建议关键字大写,表名、列名小写
  2. 每条命令最好用分号结尾,当然啦,你用\g结尾也可以
  3. 每条命令根据需要,可以进行缩进或换行(最好是关键字单独占一行),如:
mysql> SELECT
    -> name, email
    -> FROM
    -> employees;
  1. 注释

    1. 单行注释

      mysql> # select * from departments
      mysql> -- select * from departments
      
    2. 多行注释

      mysql> /*
         /*> SELECT
         /*> *
         /*> FROM
         /*> departments;
         /*> */basic | bonus
      

SQL语句分类

  • 数据查询语言(Data Query Language, DQL)

    负责进行数据查询而不会对数据本身进行修改的语句,这是最基本的SQL语句。

  • 数据定义语言 (Data Definition Language, DDL)

    负责数据结构定义与数据库对象定义的语言,由CREATEALTERDROP三个语法所组成

  • 数据操纵语言(Data Manipulation Language, DML)

    负责对数据库对象运行数据访问工作的指令集,以INSERTUPDATEDELETE三种指令为核心,分别代表插入、更新与删除。

  • 数据控制语言 (Data Control Language)

    它可以控制特定用户账户对数据表、查看表、预存程序、用户自定义函数等数据库对象的控制权。由 GRANTREVOKE 两个指令组成。

数据查询语言DQL

基础查询

SELECT 查询的字段列表 FROM 表;
- 查询的字段列表可以是字段、常量、表达式、函数等
# 查单个字段
mysql> select dept_name from departments;
# 查多个字段
mysql> select name, email from employees;
# 查所有字段
mysql> select * from departments;
# 使用表达式
mysql> select date, employee_id, basic+bonus from salary;
# 查询常量
mysql> select 100;
# 查询表达式
mysql> select 10+5;
# 查询函数
mysql> select version();
# 查询函数,统计salary共有多少行记录
mysql> select count(*) from salary;
  • 使用别名,字段名和别名之间可以用空格或关键字AS
mysql> select dept_id 部门编号, dept_name AS 部门名 from departments;
+--------------+-----------+
| 部门编号     | 部门名    |
+--------------+-----------+
|            1 | 人事部    |
|            2 | 财务部    |
|            3 | 运维部    |
|            4 | 开发部    |
|            5 | 测试部    |
|            6 | 市场部    |
|            7 | 销售部    |
|            8 | 法务部    |
+--------------+-----------+
8 rows in set (0.00 sec)
  • 去重
mysql> select dept_id from employees;
mysql> select distinct dept_id from employees;
  • 使用concat函数进行字符串拼接
mysql> select concat(name, '-', phone_number) from employees;

条件查询

SELECT 查询的字段列表 FROM 表 WHERE 条件;
  • 条件运算符,与python类似,使用
    • >: 大于
    • <: 小于
    • =: 等于
    • >=: 大于等于
    • <=: 小于等于
    • !=: 不等于
mysql> select * from departments where dept_id>3;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       4 | 开发部    |
|       5 | 测试部    |
|       6 | 市场部    |
|       7 | 销售部    |
|       8 | 法务部    |
+---------+-----------+
5 rows in set (0.00 sec)


mysql> select * from departments where dept_id<3;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       1 | 人事部    |
|       2 | 财务部    |
+---------+-----------+
2 rows in set (0.00 sec)


mysql> select * from departments where dept_id=3;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       3 | 运维部    |
+---------+-----------+
1 row in set (0.01 sec)


mysql> select * from departments where dept_id!=3;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       1 | 人事部    |
|       2 | 财务部    |
|       4 | 开发部    |
|       5 | 测试部    |
|       6 | 市场部    |
|       7 | 销售部    |
|       8 | 法务部    |
+---------+-----------+
7 rows in set (0.00 sec)


mysql> select * from departments where dept_id>=3;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       3 | 运维部    |
|       4 | 开发部    |
|       5 | 测试部    |
|       6 | 市场部    |
|       7 | 销售部    |
|       8 | 法务部    |
+---------+-----------+
6 rows in set (0.00 sec)


mysql> select * from departments where dept_id<=3;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       1 | 人事部    |
|       2 | 财务部    |
|       3 | 运维部    |
+---------+-----------+
3 rows in set (0.00 sec)
  • 逻辑运算符,and(&&)、or(||)、not(!)
mysql> select * from departments where dept_id>1 and dept_id<5;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       2 | 财务部    |
|       3 | 运维部    |
|       4 | 开发部    |
+---------+-----------+
3 rows in set (0.00 sec)


mysql> select * from departments where dept_id<3 or dept_id>6;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       1 | 人事部    |
|       2 | 财务部    |
|       7 | 销售部    |
|       8 | 法务部    |
+---------+-----------+
4 rows in set (0.00 sec)


mysql> select * from departments where not dept_id<=6;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       7 | 销售部    |
|       8 | 法务部    |
+---------+-----------+
2 rows in set (0.00 sec)
  • 模糊查询
    • like: 包含
    • between xxx and yyy: 在xxx和yyy之间的
    • in:在列表中的
    • is null:为空,相当于python的None
    • is not null:非空
# %匹配0到多个任意字符
mysql> select name, email from employees where name like '张%';
+-----------+--------------------------+
| name      | email                    |
+-----------+--------------------------+
| 张秀云    | zhangxiuyun@tedu.cn      |
| 张玉英    | zhangyuying@tarena.com   |
| 张璐      | zhanglu@tarena.com       |
| 张晨      | zhangchen@tarena.com     |
| 张桂香    | zhangguixiang@tarena.com |
| 张龙      | zhanglong@tarena.com     |
| 张桂英    | zhangguiying@tarena.com  |
| 张秀兰    | zhangxiulan@tedu.cn      |
+-----------+--------------------------+
8 rows in set (0.00 sec)


# _匹配一个字符
mysql> select name, email from employees where name like '张_';
+--------+----------------------+
| name   | email                |
+--------+----------------------+
| 张璐   | zhanglu@tarena.com   |
| 张晨   | zhangchen@tarena.com |
| 张龙   | zhanglong@tarena.com |
+--------+----------------------+
3 rows in set (0.00 sec)


mysql> select name, email from employees where name like '张__';
+-----------+--------------------------+
| name      | email                    |
+-----------+--------------------------+
| 张秀云    | zhangxiuyun@tedu.cn      |
| 张玉英    | zhangyuying@tarena.com   |
| 张桂香    | zhangguixiang@tarena.com |
| 张桂英    | zhangguiying@tarena.com  |
| 张秀兰    | zhangxiulan@tedu.cn      |
+-----------+--------------------------+
5 rows in set (0.00 sec)


mysql> select * from departments where dept_id between 3 and 5;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       3 | 运维部    |
|       4 | 开发部    |
|       5 | 测试部    |
+---------+-----------+
3 rows in set (0.00 sec)


mysql> select * from departments where dept_id in (1, 3, 5, 8);
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       1 | 人事部    |
|       3 | 运维部    |
|       5 | 测试部    |
|       8 | 法务部    |
+---------+-----------+
4 rows in set (0.00 sec)


# 匹配部门名为空的记录
mysql> select * from departments where dept_name is null;
Empty set (0.00 sec)


# 查询部门名不为空的记录
mysql> select * from departments where dept_name is not null;
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       1 | 人事部    |
|       2 | 财务部    |
|       3 | 运维部    |
|       4 | 开发部    |
|       5 | 测试部    |
|       6 | 市场部    |
|       7 | 销售部    |
|       8 | 法务部    |
+---------+-----------+
8 rows in set (0.00 sec)

排序

SELECT 查询的字段列表 FROM 表 ORDER BY 排序列表 [asc|desc];
  • 排序:默认升序
mysql> select name, birth_date from employees where birth_date>'19980101';
+-----------+------------+
| name      | birth_date |
+-----------+------------+
| 姚琳      | 1998-05-20 |
| 吴雪      | 1998-06-13 |
| 薄刚      | 2000-05-17 |
| 张玉英    | 1998-06-22 |
| 刘倩      | 1998-10-27 |
| 申峰      | 1999-01-13 |
| 陈勇      | 1998-02-04 |
| 厉秀云    | 1999-09-08 |
| 张桂英    | 1999-05-31 |
| 赵峰      | 1998-03-06 |
| 蒙梅      | 2000-09-01 |
| 陈欢      | 1998-07-01 |
| 马磊      | 2000-08-07 |
| 赵秀梅    | 1998-09-25 |
+-----------+------------+
14 rows in set (0.00 sec)

# 默认升序排列
mysql> select name, birth_date from employees where birth_date>'19980101' order by birth_date;
+-----------+------------+
| name      | birth_date |
+-----------+------------+
| 陈勇      | 1998-02-04 |
| 赵峰      | 1998-03-06 |
| 姚琳      | 1998-05-20 |
| 吴雪      | 1998-06-13 |
| 张玉英    | 1998-06-22 |
| 陈欢      | 1998-07-01 |
| 赵秀梅    | 1998-09-25 |
| 刘倩      | 1998-10-27 |
| 申峰      | 1999-01-13 |
| 张桂英    | 1999-05-31 |
| 厉秀云    | 1999-09-08 |
| 薄刚      | 2000-05-17 |
| 马磊      | 2000-08-07 |
| 蒙梅      | 2000-09-01 |
+-----------+------------+
14 rows in set (0.00 sec)

# 降序排列
mysql> select name, birth_date from employees where birth_date>'19980101' order by birth_date desc;
+-----------+------------+
| name      | birth_date |
+-----------+------------+
| 蒙梅      | 2000-09-01 |
| 马磊      | 2000-08-07 |
| 薄刚      | 2000-05-17 |
| 厉秀云    | 1999-09-08 |
| 张桂英    | 1999-05-31 |
| 申峰      | 1999-01-13 |
| 刘倩      | 1998-10-27 |
| 赵秀梅    | 1998-09-25 |
| 陈欢      | 1998-07-01 |
| 张玉英    | 1998-06-22 |
| 吴雪      | 1998-06-13 |
| 姚琳      | 1998-05-20 |
| 赵峰      | 1998-03-06 |
| 陈勇      | 1998-02-04 |
+-----------+------------+
14 rows in set (0.00 sec)


# 查询2015年1月10号员工工资情况
mysql> select date, employee_id, basic, bonus from salary where date='20150110';

# 查询2015年1月10号员工工资情况,以基本工资进行降序排列;如果基本工资相同,再以奖金升序排列
mysql> select date, employee_id, basic, bonus from salary where date='20150110' order by basic desc, bonus;

# 查询2015年1月10号员工工资情况,以工资总额为排序条件
mysql> select date, employee_id, basic, bonus, basic+bonus as total from salary where date='20150110' order by total;

常用函数

分类

  • 按使用方式分为:

    • 单行函数
    • 分组函数
  • 按用途分为:

    • 字符函数
    • 数学函数
    • 日期函数
    • 流程控制函数
  • 用法:

SELECT 函数(参数) FROM 表;

函数应用

字符函数实例:

  • LENGTH(str):返字符串长度,以字节为单位
mysql> select length('abc');
+---------------+
| length('abc') |
+---------------+
|             3 |
+---------------+
1 row in set (0.00 sec)


mysql> select length('你好');
+------------------+
| length('你好')   |
+------------------+
|                6 |
+------------------+
1 row in set (0.00 sec)


mysql> select name, email, length(email) from employees where name='李平';
+--------+----------------+---------------+
| name   | email          | length(email) |
+--------+----------------+---------------+
| 李平   | liping@tedu.cn |            14 |
+--------+----------------+---------------+
1 row in set (0.00 sec)
  • CHAR_LENGTH(str): 返回字符串长度,以字符为单位
mysql> select char_length('abc');
+--------------------+
| char_length('abc') |
+--------------------+
|                  3 |
+--------------------+
1 row in set (0.00 sec)


mysql> select char_length('你好');
+-----------------------+
| char_length('你好')   |
+-----------------------+
|                     2 |
+-----------------------+
1 row in set (0.00 sec)
  • CONCAT(s1,s2,...): 返回连接参数产生的字符串,一个或多个待拼接的内容,任意一个为NULL则返回值为NULL
# 拼接字符串
mysql> select concat(dept_id, '-', dept_name) from departments;
+---------------------------------+
| concat(dept_id, '-', dept_name) |
+---------------------------------+
| 1-人事部                        |
| 2-财务部                        |
| 3-运维部                        |
| 4-开发部                        |
| 5-测试部                        |
| 6-市场部                        |
| 7-销售部                        |
| 8-法务部                        |
+---------------------------------+
8 rows in set (0.00 sec)
  • UPPER(str)和UCASE(str): 将字符串中的字母全部转换成大写
mysql> select name, upper(email) from employees where name like '李%';
+-----------+----------------------+
| name      | upper(email)         |
+-----------+----------------------+
| 李玉英    | LIYUYING@TEDU.CN     |
| 李平      | LIPING@TEDU.CN       |
| 李建华    | LIJIANHUA@TARENA.COM |
| 李莹      | LIYING@TEDU.CN       |
| 李柳      | LILIU@TARENA.COM     |
| 李慧      | LIHUI@TARENA.COM     |
| 李静      | LIJING@TARENA.COM    |
| 李瑞      | LIRUI@TARENA.COM     |
+-----------+----------------------+
8 rows in set (0.00 sec)
  • LOWER(str)和LCASE(str):将str中的字母全部转换成小写
# 转小写
mysql> select lower('HelloWorld');
+---------------------+
| lower('HelloWorld') |
+---------------------+
| helloworld          |
+---------------------+
1 row in set (0.00 sec)
  • SUBSTR(s, start, length): 从子符串s的start位置开始,取出length长度的子串,位置从1开始计算
mysql> select substr('hello world', 7);
+--------------------------+
| substr('hello world', 7) |
+--------------------------+
| world                    |
+--------------------------+
1 row in set (0.00 sec)


# 取子串,下标从7开始取出3个
mysql> select substr('hello world', 7, 3);
+-----------------------------+
| substr('hello world', 7, 3) |
+-----------------------------+
| wor                         |
+-----------------------------+
1 row in set (0.00 sec)
  • INSTR(str,str1):返回str1参数,在str参数内的位置
# 子串在字符串中的位置
mysql> select instr('hello world', 'or');
+----------------------------+
| instr('hello world', 'or') |
+----------------------------+
|                          8 |
+----------------------------+
1 row in set (0.00 sec)


mysql> select instr('hello world', 'ol');
+----------------------------+
| instr('hello world', 'ol') |
+----------------------------+
|                          0 |
+----------------------------+
1 row in set (0.00 sec)
  • TRIM(s): 返回字符串s删除了两边空格之后的字符串
mysql> select trim('  hello world.  ');
+--------------------------+
| trim('  hello world.  ') |
+--------------------------+
| hello world.             |
+--------------------------+
1 row in set (0.00 sec)

数学函数实例

  • ABS(x):返回x的绝对值
mysql> select abs(-10);
+----------+
| abs(-10) |
+----------+
|       10 |
+----------+
1 row in set (0.00 sec)
  • PI(): 返回圆周率π,默认显示6位小数
mysql> select pi();
+----------+
| pi()     |
+----------+
| 3.141593 |
+----------+
1 row in set (0.00 sec)
  • MOD(x,y): 返回x被y除后的余数
mysql> select mod(10, 3);
+------------+
| mod(10, 3) |
+------------+
|          1 |
+------------+
1 row in set (0.00 sec)
  • CEIL(x)、CEILING(x): 返回不小于x的最小整数
mysql> select ceil(10.1);
+------------+
| ceil(10.1) |
+------------+
|         11 |
+------------+
1 row in set (0.00 sec)
  • FLOOR(x): 返回不大于x的最大整数
mysql> select floor(10.9);
+-------------+
| floor(10.9) |
+-------------+
|          10 |
+-------------+
1 row in set (0.00 sec)
  • ROUND(x)、ROUND(x,y): 前者返回最接近于x的整数,即对x进行四舍五入;后者返回最接近x的数,其值保留到小数点后面y位,若y为负值,则将保留到x到小数点左边y位
mysql> select round(10.6666);
+----------------+
| round(10.6666) |
+----------------+
|             11 |
+----------------+
1 row in set (0.00 sec)


mysql> select round(10.6666, 2);
+-------------------+
| round(10.6666, 2) |
+-------------------+
|             10.67 |
+-------------------+
1 row in set (0.00 sec)

日期和时间函数实例

  • CURDATE()、CURRENT_DATE(): 将当前日期按照"YYYY-MM-DD"或者"YYYYMMDD"格式的值返回,具体格式根据函数用在字符串或是数字语境中而定
mysql> select curdate();
+------------+
| curdate()  |
+------------+
| 2021-03-09 |
+------------+
1 row in set (0.00 sec)


mysql> select curdate() + 0;
+---------------+
| curdate() + 0 |
+---------------+
|      20210309 |
+---------------+
1 row in set (0.00 sec)
  • NOW(): 返回当前日期和时间值,格式为"YYYY_MM-DD HH:MM:SS"或"YYYYMMDDHHMMSS",具体格式根据函数用在字符串或数字语境中而定
mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2021-03-09 02:28:26 |
+---------------------+
1 row in set (0.00 sec)


mysql> select now() + 0;
+----------------+
| now() + 0      |
+----------------+
| 20210309022848 |
+----------------+
1 row in set (0.00 sec)
  • UNIX_TIMESTAMP()、UNIX_TIMESTAMP(date): 前者返回一个格林尼治标准时间1970-01-01 00:00:00到现在的秒数,后者返回一个格林尼治标准时间1970-01-01 00:00:00到指定时间的秒数
mysql> select unix_timestamp();
+------------------+
| unix_timestamp() |
+------------------+
|       1615275274 |
+------------------+
1 row in set (0.00 sec)
  • FROM_UNIXTIME(date): 和UNIX_TIMESTAMP互为反函数,把UNIX时间戳转换为普通格式的时间
mysql> select from_unixtime(0);
+---------------------+
| from_unixtime(0)    |
+---------------------+
| 1969-12-31 19:00:00 |
+---------------------+
1 row in set (0.00 sec)
  • MONTH(date)和MONTHNAME(date):前者返回指定日期中的月份,后者返回指定日期中的月份的名称
mysql> select month('20211001120000');
+-------------------------+
| month('20211001120000') |
+-------------------------+
|                      10 |
+-------------------------+
1 row in set (0.00 sec)


mysql> select monthname('20211001120000');
+-----------------------------+
| monthname('20211001120000') |
+-----------------------------+
| October                     |
+-----------------------------+
1 row in set (0.00 sec)
  • DAYNAME(d)、DAYOFWEEK(d)、WEEKDAY(d): DAYNAME(d)返回d对应的工作日的英文名称,如Sunday、Monday等;DAYOFWEEK(d)返回的对应一周中的索引,1表示周日、2表示周一;WEEKDAY(d)表示d对应的工作日索引,0表示周一,1表示周二
mysql> select dayname('20211001120000');
+---------------------------+
| dayname('20211001120000') |
+---------------------------+
| Friday                    |
+---------------------------+
1 row in set (0.00 sec)


mysql> select dayname('20211001');
+---------------------+
| dayname('20211001') |
+---------------------+
| Friday              |
+---------------------+
1 row in set (0.00 sec)
  • WEEK(d): 计算日期d是一年中的第几周
mysql> select week('20211001');
+------------------+
| week('20211001') |
+------------------+
|               39 |
+------------------+
1 row in set (0.00 sec)
  • DAYOFYEAR(d)、DAYOFMONTH(d): 前者返回d是一年中的第几天,后者返回d是一月中的第几天
mysql> select dayofyear('20211001');
+-----------------------+
| dayofyear('20211001') |
+-----------------------+
|                   274 |
+-----------------------+
1 row in set (0.00 sec)
  • YEAR(date)、QUARTER(date)、MINUTE(time)、SECOND(time): YEAR(date)返回指定日期对应的年份,范围是1970到2069;QUARTER(date)返回date对应一年中的季度,范围是1到4;MINUTE(time)返回time对应的分钟数,范围是0~59;SECOND(time)返回制定时间的秒值
mysql> select year('20211001');
+------------------+
| year('20211001') |
+------------------+
|             2021 |
+------------------+
1 row in set (0.00 sec)


mysql> select quarter('20211001');
+---------------------+
| quarter('20211001') |
+---------------------+
|                   4 |
+---------------------+
1 row in set (0.00 sec)

流程控制函数实例

  • IF(expr,v1,v2): 如果expr是TRUE则返回v1,否则返回v2
mysql> select if(3>0, 'yes', 'no');
+----------------------+
| if(3>0, 'yes', 'no') |
+----------------------+
| yes                  |
+----------------------+
1 row in set (0.00 sec)



mysql> select name, dept_id, if(dept_id=1, '人事部', '非人事部')  from employees where name='张亮';
+--------+---------+--------------------------------------------+
| name   | dept_id | if(dept_id=1, '人事部', '非人事部')        |
+--------+---------+--------------------------------------------+
| 张亮   |       7 | 非人事部                                   |
+--------+---------+--------------------------------------------+
1 row in set (0.00 sec)
  • IFNULL(v1,v2): 如果v1不为NULL,则返回v1,否则返回v2
mysql> select dept_id, dept_name, ifnull(dept_name, '未设置') from departments;
+---------+-----------+--------------------------------+
| dept_id | dept_name | ifnull(dept_name, '未设置')    |
+---------+-----------+--------------------------------+
|       1 | 人事部    | 人事部                         |
|       2 | 财务部    | 财务部                         |
|       3 | 运维部    | 运维部                         |
|       4 | 开发部    | 开发部                         |
|       5 | 测试部    | 测试部                         |
|       6 | 市场部    | 市场部                         |
|       7 | 销售部    | 销售部                         |
|       8 | 法务部    | 法务部                         |
+---------+-----------+--------------------------------+
8 rows in set (0.00 sec)


mysql> insert into departments(dept_id) values(9);
mysql> select dept_id, dept_name, ifnull(dept_name, '未设置') from departments; 
+---------+-----------+--------------------------------+
| dept_id | dept_name | ifnull(dept_name, '未设置')    |
+---------+-----------+--------------------------------+
|       1 | 人事部    | 人事部                         |
|       2 | 财务部    | 财务部                         |
|       3 | 运维部    | 运维部                         |
|       4 | 开发部    | 开发部                         |
|       5 | 测试部    | 测试部                         |
|       6 | 市场部    | 市场部                         |
|       7 | 销售部    | 销售部                         |
|       8 | 法务部    | 法务部                         |
|       9 | NULL      | 未设置                         |
+---------+-----------+--------------------------------+
9 rows in set (0.00 sec)
  • CASE expr WHEN v1 THEN r1 [WHEN v2 THEN v2] [ELSE rn] END: 如果expr等于某个vn,则返回对应位置THEN后面的结果,如果与所有值都不想等,则返回ELSE后面的rn
mysql> select dept_id, dept_name,
    -> case dept_name
    -> when '运维部' then '技术部门'
    -> when '开发部' then '技术部门'
    -> when '测试部' then '技术部门'
    -> when null then '未设置'
    -> else '非技术部门'
    -> end as '部门类型'
    -> from departments;
+---------+-----------+-----------------+
| dept_id | dept_name | 部门类型        |
+---------+-----------+-----------------+
|       1 | 人事部    | 非技术部门      |
|       2 | 财务部    | 非技术部门      |
|       3 | 运维部    | 技术部门        |
|       4 | 开发部    | 技术部门        |
|       5 | 测试部    | 技术部门        |
|       6 | 市场部    | 非技术部门      |
|       7 | 销售部    | 非技术部门      |
|       8 | 法务部    | 非技术部门      |
|       9 | NULL      | 非技术部门      |
+---------+-----------+-----------------+
9 rows in set (0.00 sec)


mysql> select dept_id, dept_name,
    -> case 
    -> when dept_name='运维部' then '技术部门'
    -> when dept_name='开发部' then '技术部门'
    -> when dept_name='测试部' then '技术部门'
    -> when dept_name is null then '未设置'
    -> else '非技术部门'
    -> end as '部门类型'
    -> from departments;
+---------+-----------+-----------------+
| dept_id | dept_name | 部门类型        |
+---------+-----------+-----------------+
|       1 | 人事部    | 非技术部门      |
|       2 | 财务部    | 非技术部门      |
|       3 | 运维部    | 技术部门        |
|       4 | 开发部    | 技术部门        |
|       5 | 测试部    | 技术部门        |
|       6 | 市场部    | 非技术部门      |
|       7 | 销售部    | 非技术部门      |
|       8 | 法务部    | 非技术部门      |
|       9 | NULL      | 未设置          |
+---------+-----------+-----------------+
9 rows in set (0.00 sec)

分组函数

用于统计,又称为聚合函数或统计函数

  • sum() :求和
mysql> select employee_id, sum(basic+bonus) from salary where employee_id=10 and year(date)=2018;
+-------------+------------------+
| employee_id | sum(basic+bonus) |
+-------------+------------------+
|          10 |           116389 |
+-------------+------------------+
1 row in set (0.00 sec)
  • avg() :求平均值
mysql> select employee_id, avg(basic+bonus) from salary where employee_id=10 and year(date)=2018;
+-------------+------------------+
| employee_id | avg(basic+bonus) |
+-------------+------------------+
|          10 |       29097.2500 |
+-------------+------------------+
1 row in set (0.00 sec)
  • max() :求最大值
mysql> select employee_id, max(basic+bonus) from salary where employee_id=10 and year(date)=2018;
+-------------+------------------+
| employee_id | max(basic+bonus) |
+-------------+------------------+
|          10 |            31837 |
+-------------+------------------+
1 row in set (0.00 sec)
  • min() :求最小值
mysql> select employee_id, min(basic+bonus) from salary where employee_id=10 and year(date)=2018;
+-------------+------------------+
| employee_id | min(basic+bonus) |
+-------------+------------------+
|          10 |            24837 |
+-------------+------------------+
1 row in set (0.00 sec)
  • count() :计算个数
mysql> select count(*) from departments;
+----------+
| count(*) |
+----------+
|        9 |
+----------+
1 row in set (0.00 sec)

分组查询

  • 在对数据表中数据进行统计时,可能需要按照一定的类别分别进行统计。比如查询每个部门的员工数。

  • 使用GROUP BY按某个字段,或者多个字段中的值,进行分组,字段中值相同的为一组

语法格式

  • 查询列表必须是分组函数和出现在GROUP BY后面的字段
  • 通常而言,分组前的数据筛选放在where子句中,分组后的数据筛选放在having子句中
SELECT 字段名1(要求出现在group by后面),分组函数(),……
FROM 表名
WHERE 条件
GROUP BY 字段名1,字段名2
HAVING 过滤条件
ORDER BY 字段;

应用实例

  • 查询每个部门的人数
mysql> select dept_id, count(*) from employees group by dept_id;
+---------+----------+
| dept_id | count(*) |
+---------+----------+
|       1 |        8 |
|       2 |        5 |
|       3 |        6 |
|       4 |       55 |
|       5 |       12 |
|       6 |        9 |
|       7 |       35 |
|       8 |        3 |
+---------+----------+
8 rows in set (0.00 sec)
  • 查询每个部门中年龄最大的员工
mysql> select dept_id, min(birth_date) from employees group by dept_id;
+---------+-----------------+
| dept_id | min(birth_date) |
+---------+-----------------+
|       1 | 1971-08-19      |
|       2 | 1971-11-02      |
|       3 | 1971-09-09      |
|       4 | 1972-01-31      |
|       5 | 1971-08-14      |
|       6 | 1973-04-14      |
|       7 | 1971-12-10      |
|       8 | 1989-05-19      |
+---------+-----------------+
8 rows in set (0.00 sec)
  • 查询每个部门入职最晚员工的入职时间
mysql> select dept_id, max(hire_date) from employees group by dept_id;
+---------+----------------+
| dept_id | max(hire_date) |
+---------+----------------+
|       1 | 2018-11-21     |
|       2 | 2018-09-03     |
|       3 | 2019-07-04     |
|       4 | 2021-02-04     |
|       5 | 2019-06-08     |
|       6 | 2017-10-07     |
|       7 | 2020-08-21     |
|       8 | 2019-11-14     |
+---------+----------------+
8 rows in set (0.00 sec)
  • 统计各部门使用tedu.cn邮箱的员工人数
mysql> select dept_id, count(*) from employees where email like '%@tedu.cn' group by dept_id;
+---------+----------+
| dept_id | count(*) |
+---------+----------+
|       1 |        5 |
|       2 |        2 |
|       3 |        4 |
|       4 |       32 |
|       5 |        7 |
|       6 |        5 |
|       7 |       15 |
|       8 |        1 |
+---------+----------+
8 rows in set (0.00 sec)
  • 查看员工2018年工资总收入,按总收入进行降序排列
mysql> select employee_id, sum(basic+bonus) as total from salary where year(date)=2018 group by employee_id order by total desc;
  • 查询部门人数少于10人
mysql> select dept_id, count(*) from employees where count(*)<10 group by dept_id;
ERROR 1111 (HY000): Invalid use of group function


mysql> select dept_id, count(*) from employees group by dept_id having count(*)<10;
+---------+----------+
| dept_id | count(*) |
+---------+----------+
|       1 |        8 |
|       2 |        5 |
|       3 |        6 |
|       6 |        9 |
|       8 |        3 |
+---------+----------+
5 rows in set (0.00 sec)

连接查询

  • 也叫多表查询。常用于查询字段来自于多张表
  • 如果直接查询两张表,将会得到笛卡尔积
mysql> select name, dept_name from employees, departments;
  • 通过添加有效的条件可以进行查询结果的限定
mysql> select name, dept_name from employees, departments where employees.dept_id=departments.dept_id;

连接分类

按功能分类

  • 内连接(重要)
    • 等值连接
    • 非等值连接
    • 自连接
  • 外连接
    • 左外连接(重要)
    • 右外连接(重要)
    • 全外连接(mysql不支持,可以使用UNION实现相同的效果)
  • 交叉连接

按年代分类

  • SQL92标准:仅支持内连接
  • SQL99标准:支持所功能的连接

SQL99标准多表查询

  • 语法格式
SELECT 字段... 
FROM 表1 [AS] 别名 [连接类型]
JOIN 表2 [AS] 别名
ON 连接条件
WHERE 分组前筛选条件
GROUP BY 分组
HAVING 分组后筛选条件
ORDER BY 排序字段

内连接

  • 语法格式
select 查询列表
from 表1 别名
inner join 表2 别名 on 连接条件
inner join 表3 别名 on 连接条件
[where 筛选条件]
[group by 分组]
[having 分组后筛选]
[order by 排序列表]
等值连接
  • 查询每个员工所在的部门名
mysql> select name, dept_name
    -> from employees
    -> inner join departments
    -> on employees.dept_id=departments.dept_id;
  • 查询每个员工所在的部门名,使用别名
mysql> select name, dept_name
    -> from employees as e
    -> inner join departments as d
    -> on e.dept_id=d.dept_id;
  • 查询每个员工所在的部门名,使用别名。两个表中的同名字段,必须指定表名
mysql> select name, d.dept_id, dept_name
    -> from employees as e
    -> inner join departments as d
    -> on e.dept_id=d.dept_id;
  • 查询11号员工的名字及2018年每个月工资
mysql> select name, date, basic+bonus as total
    -> from employees as e
    -> inner join salary as s
    -> on e.employee_id=s.employee_id
    -> where year(s.date)=2018 and e.employee_id=11;
  • 查询2018年每个员工的总工资
mysql> select name, sum(basic+bonus) from employees
    -> inner join salary
    -> on employees.employee_id=salary.employee_id
    -> where year(salary.date)=2018
    -> group by name;
  • 查询2018年每个员工的总工资,按工资升序排列
mysql> select name, sum(basic+bonus) as total from employees as e
    -> inner join salary as s
    -> on e.employee_id=s.employee_id
    -> where year(s.date)=2018
    -> group by name
    -> order by total;
  • 查询2018年总工资大于30万的员工,按工资降序排列
 mysql> select name, sum(basic+bonus) as total from employees as e
    -> inner join salary as s
    -> on e.employee_id=s.employee_id
    -> where year(s.date)=2018
    -> group by name
    -> having total>300000
    -> order by total desc;
非等值连接

附:创建工资级别表

创建表语法:

CREATE TABLE 表名称
(
列名称1 数据类型,
列名称2 数据类型,
列名称3 数据类型,
....
)

创建工资级别表:

  • id:主键。仅作为表的行号
  • grade:工资级别,共ABCDE五类
  • low:该级别最低工资
  • high:该级别最高工资
mysql> use nsd2021;
mysql> create table wage_grade
    -> (
    -> id int,
    -> grade char(1),
    -> low int,
    -> high int,
    -> primary key (id));

向表中插入数据:

  • 语法:
INSERT INTO 表名称 VALUES (值1, 值2,....);
  • 向wage_grade表中插入五行数据:
mysql> insert into wage_grade values
    -> (1, 'A', 5000, 8000),
    -> (2, 'B', 8001, 10000),
    -> (3, 'C', 10001, 15000),
    -> (4, 'D', 15001, 20000),
    -> (5, 'E', 20001, 1000000);
  • 查询2018年12月员工基本工资级别
mysql> select employee_id, date, basic, grade
    -> from salary as s
    -> inner join wage_grade as g
    -> on s.basic between g.low and g.high
    -> where year(date)=2018 and month(date)=12;
  • 查询2018年12月员工各基本工资级别的人数
mysql> select grade, count(*)
    -> from salary as s
    -> inner join wage_grade as g
    -> on s.basic between g.low and g.high
    -> where year(date)=2018 and month(date)=12
    -> group by grade;
+-------+----------+
| grade | count(*) |
+-------+----------+
| A     |       13 |
| B     |       12 |
| C     |       30 |
| D     |       32 |
| E     |       33 |
+-------+----------+
5 rows in set (0.00 sec)
  • 查询2018年12月员工基本工资级别,员工需要显示姓名
mysql> select name, date, basic, grade
    -> from employees as e
    -> inner join salary as s
    -> on e.employee_id=s.employee_id
    -> inner join wage_grade as g
    -> on s.basic between g.low and g.high
    -> where year(date)=2018 and month(date)=12;
自连接
  • 要点:

    • 将一张表作为两张使用
    • 每张表起一个别名
  • 查看哪些员的生日月份与入职月份相同

mysql> select e.name, e.hire_date, em.birth_date
    -> from employees as e
    -> inner join employees as em
    -> on month(e.hire_date)=month(em.birth_date)
    -> and e.employee_id=em.employee_id;
+-----------+------------+------------+
| name      | hire_date  | birth_date |
+-----------+------------+------------+
| 李玉英    | 2012-01-19 | 1974-01-25 |
| 郑静      | 2018-02-03 | 1997-02-14 |
| 林刚      | 2007-09-19 | 1990-09-23 |
| 刘桂兰    | 2003-10-14 | 1982-10-11 |
| 张亮      | 2015-08-10 | 1996-08-25 |
| 许欣      | 2011-09-09 | 1982-09-25 |
| 王荣      | 2019-11-14 | 1999-11-22 |
+-----------+------------+------------+
7 rows in set (0.00 sec)

外连接

  • 常用于查询一个表中有,另一个表中没有的记录

  • 如果从表中有和它匹配的,则显示匹配的值

  • 如要从表中没有和它匹配的,则显示NULL

  • 外连接查询结果=内连接查询结果+主表中有而从表中没有的记录

  • 左外连接中,left join左边的是主表

  • 右外连接中,right join右边的是主表

  • 左外连接和右外连接可互换,实现相同的目标

左外连接
  • 语法
SELECT tb1.字段..., tb2.字段
FROM table1 AS tb1
LEFT OUTER JOIN table2 AS tb2 
ON tb1.字段=tb2.字段
  • 查询所有部门的人员以及没有员工的部门
mysql> select d.*, e.name
    -> from departments as d
    -> left outer join employees as e
    -> on d.dept_id=e.dept_id;
右外连接
  • 语法
SELECT tb1.字段..., tb2.字段
FROM table1 AS tb1
RIGHT OUTER JOIN table2 AS tb2 
ON tb1.字段=tb2.字段
  • 查询所有部门的人员以及没有员工的部门
mysql> select d.*, e.name
    -> from employees as e
    -> right outer join departments as d
    -> on d.dept_id=e.dept_id;
交叉连接
  • 返回笛卡尔积
  • 语法:
SELECT <字段名> FROM <表1> CROSS JOIN <表2> [WHERE子句]
  • 查询员工表和部门表的笛卡尔积
mysql> select name, dept_name
    -> from employees
    -> cross join departments;

附:授予管理员root可以通过任意地址访问数据库,密码是NSD2021@tedu.cn。默认情况下,root只允许在本机访问

mysql> grant all on *.* to root@'%' identified by 'NSD2021@tedu.cn';

向部门表中插入数据:

mysql> insert into departments(dept_name) values('采购部');

子查询

  • 子查询就是指的在一个完整的查询语句之中,嵌套若干个不同功能的小查询,从而一起完成复杂查询的一种编写形式

子查询返回的数据分类

  • 单行单列:返回的是一个具体列的内容,可以理解为一个单值数据
  • 单行多列:返回一行数据中多个列的内容
  • 多行单列:返回多行记录之中同一列的内容,相当于给出了一个操作范围
  • 多行多列:查询返回的结果是一张临时表

子查询常出现的位置

  • select之后:仅支持单行单列
  • from之后:支持多行多列
  • where或having之后:支持单行单列、单行多列、多行单列

子查询实例

单行单列

  • 查询运维部所有员工信息

    • 分析:

    • 首先从departments表中查出运维部的编号

      mysql> select dept_id from departments where dept_name='运维部';
      +---------+
      | dept_id |
      +---------+
      |       3 |
      +---------+
      1 row in set (0.00 sec)
      
    • 再从employees表中查找该部门编号和运维部编号相同的员工

      mysql> select *
          -> from employees
          -> where dept_id=(
          ->   select dept_id from departments where dept_name='运维部'
          -> );
      
  • 查询2018年12月所有比100号员工基本工资高的工资信息

    • 分析:

    • 首先查到2018年12月100号员工的基本工资

      mysql> select basic from salary
          -> where year(date)=2018 and month(date)=12 and employee_id=100;
      +-------+
      | basic |
      +-------+
      | 14585 |
      +-------+
      1 row in set (0.00 sec)
      
    • 再查询2018年12月所有比100号员工基本工资高的工资信息

      mysql> select * from salary
          -> where year(date)=2018 and month(date)=12 and basic>(
          ->   select basic from salary
          ->   where year(date)=2018 and month(date)=12 and employee_id=100
          -> );
      
  • 查询部门员工人数比开发部人数少的部门

    • 分析:

    • 查询开发部部门编号

      mysql> select dept_id from departments where dept_name='开发部';
      +---------+
      | dept_id |
      +---------+
      |       4 |
      +---------+
      1 row in set (0.00 sec)
      
    • 查询开发部人数

      mysql> select count(*) from employees
          -> where dept_id=(
          ->   select dept_id from departments where dept_name='开发部'
          -> );
      +----------+
      | count(*) |
      +----------+
      |       55 |
      +----------+
      1 row in set (0.00 sec)
      
    • 分组查询各部门人数

      mysql> select count(*), dept_id from employees group by dept_id;
      +----------+---------+
      | count(*) | dept_id |
      +----------+---------+
      |        8 |       1 |
      |        5 |       2 |
      |        6 |       3 |
      |       55 |       4 |
      |       12 |       5 |
      |        9 |       6 |
      |       35 |       7 |
      |        3 |       8 |
      +----------+---------+
      8 rows in set (0.01 sec)
      
    • 查询部门员工人数比开发部人数少的部门

      mysql> select count(*), dept_id from employees group by dept_id
          -> having count(*)<(
          ->   select count(*) from employees
          ->   where dept_id=(
          ->     select dept_id from departments where dept_name='开发部'
          ->   )
          -> );
      +----------+---------+
      | count(*) | dept_id |
      +----------+---------+
      |        8 |       1 |
      |        5 |       2 |
      |        6 |       3 |
      |       12 |       5 |
      |        9 |       6 |
      |       35 |       7 |
      |        3 |       8 |
      +----------+---------+
      7 rows in set (0.00 sec)
      
  • 查询每个部门的人数

    • 分析:

    • 查询所有部门的信息

      mysql> select d.* from departments as d;
      +---------+-----------+
      | dept_id | dept_name |
      +---------+-----------+
      |       1 | 人事部    |
      |       2 | 财务部    |
      |       3 | 运维部    |
      |       4 | 开发部    |
      |       5 | 测试部    |
      |       6 | 市场部    |
      |       7 | 销售部    |
      |       8 | 法务部    |
      |       9 | NULL      |
      +---------+-----------+
      9 rows in set (0.00 sec)
      
    • 查询每个部门的人数

      mysql> select d.*, (
          ->  select count(*) from employees as e
          ->   where d.dept_id=e.dept_id
          -> ) as amount
          -> from departments as d;
      +---------+-----------+--------+
      | dept_id | dept_name | amount |
      +---------+-----------+--------+
      |       1 | 人事部    |      8 |
      |       2 | 财务部    |      5 |
      |       3 | 运维部    |      6 |
      |       4 | 开发部    |     55 |
      |       5 | 测试部    |     12 |
      |       6 | 市场部    |      9 |
      |       7 | 销售部    |     35 |
      |       8 | 法务部    |      3 |
      |       9 | NULL      |      0 |
      +---------+-----------+--------+
      9 rows in set (0.00 sec)
      

多行单列

  • 查询人事部和财务部员工信息

    • 分析:

    • 查询人事部和财务部编号

      mysql> select dept_id from departments
          -> where dept_name in ('人事部', '财务部');
      +---------+
      | dept_id |
      +---------+
      |       1 |
      |       2 |
      +---------+
      2 rows in set (0.00 sec)
      
    • 查询部门编号是两个部门编号的员工信息

      mysql> select * from employees
          -> where dept_id in (
          ->   select dept_id from departments
          ->   where dept_name in ('人事部', '财务部')
          -> );
      
  • 查询人事部2018年12月所有员工工资

    • 分析:

    • 查询人事部部门编号

      mysql> select dept_id from departments where dept_name='人事部';
      +---------+
      | dept_id |
      +---------+
      |       1 |
      +---------+
      1 row in set (0.00 sec)
      
    • 查询人事部员的编号

      mysql> select employee_id from employees
          -> where dept_id=(
          ->   select dept_id from departments where dept_name='人事部'
          -> );
      +-------------+
      | employee_id |
      +-------------+
      |           1 |
      |           2 |
      |           3 |
      |           4 |
      |           5 |
      |           6 |
      |           7 |
      |           8 |
      +-------------+
      8 rows in set (0.00 sec)
      
    • 查询2018年12月人事部所有员工工资

      mysql> select * from salary
          -> where year(date)=2018 and month(date)=12 and employee_id in (
          ->   select employee_id from employees
          ->   where dept_id=(
          ->     select dept_id from departments where dept_name='人事部'
          ->   )
          -> );
      +------+------------+-------------+-------+-------+
      | id   | date       | employee_id | basic | bonus |
      +------+------------+-------------+-------+-------+
      | 6252 | 2018-12-10 |           1 | 17016 |  7000 |
      | 6253 | 2018-12-10 |           2 | 20662 |  9000 |
      | 6254 | 2018-12-10 |           3 |  9724 |  8000 |
      | 6255 | 2018-12-10 |           4 | 17016 |  2000 |
      | 6256 | 2018-12-10 |           5 | 17016 |  3000 |
      | 6257 | 2018-12-10 |           6 | 17016 |  1000 |
      | 6258 | 2018-12-10 |           7 | 23093 |  4000 |
      | 6259 | 2018-12-10 |           8 | 23093 |  2000 |
      +------+------------+-------------+-------+-------+
      8 rows in set (0.00 sec)
      

单行多列

  • 查找2018年12月基本工资和奖金都是最高的工资信息

    • 分析:

    • 查询2018年12月最高的基本工资

      mysql> select max(basic) from salary
          -> where year(date)=2018 and month(date)=12;
      +------------+
      | max(basic) |
      +------------+
      |      25524 |
      +------------+
      1 row in set (0.00 sec)
      
    • 查询2018年12月最高的奖金

      mysql> select max(bonus) from salary
          -> where year(date)=2018 and month(date)=12;
      +------------+
      | max(bonus) |
      +------------+
      |      11000 |
      +------------+
      1 row in set (0.00 sec)
      
    • 查询

      mysql> select * from salary
          -> where year(date)=2018 and month(date)=12 and basic=(
          ->   select max(basic) from salary
          ->   where year(date)=2018 and month(date)=12
          -> ) and bonus=(
          ->   select max(bonus) from salary
          ->   where year(date)=2018 and month(date)=12
          -> );
      +------+------------+-------------+-------+-------+
      | id   | date       | employee_id | basic | bonus |
      +------+------------+-------------+-------+-------+
      | 6368 | 2018-12-10 |         117 | 25524 | 11000 |
      +------+------------+-------------+-------+-------+
      1 row in set (0.01 sec)
      

多行多列

  • 查询3号部门及其部门内员工的编号、名字和email

    • 分析

    • 查询3号部门和员工的所有信息

      mysql> select d.dept_name, e.*
          -> from departments as d
          -> inner join employees as e
          -> on d.dept_id=e.dept_id;
      
    • 将上述结果当成一张临时表,必须为其起别名。再从该临时表中查询

      mysql> select dept_id, dept_name, employee_id, name, email
          -> from (
          ->   select d.dept_name, e.*
          ->   from departments as d
          ->   inner join employees as e
          ->   on d.dept_id=e.dept_id
          -> ) as tmp_table
          -> where dept_id=3;
      +---------+-----------+-------------+-----------+--------------------+
      | dept_id | dept_name | employee_id | name      | email              |
      +---------+-----------+-------------+-----------+--------------------+
      |       3 | 运维部    |          14 | 廖娜      | liaona@tarena.com  |
      |       3 | 运维部    |          15 | 窦红梅    | douhongmei@tedu.cn |
      |       3 | 运维部    |          16 | 聂想      | niexiang@tedu.cn   |
      |       3 | 运维部    |          17 | 陈阳      | chenyang@tedu.cn   |
      |       3 | 运维部    |          18 | 戴璐      | dailu@tedu.cn      |
      |       3 | 运维部    |          19 | 陈斌      | chenbin@tarena.com |
      +---------+-----------+-------------+-----------+--------------------+
      6 rows in set (0.00 sec)
      

分页查询

  • 使用SELECT查询时,如果结果集数据量很大,比如几万行数据,放在一个页面显示的话数据量太大,不如分页显示,每次显示100条

  • 要实现分页功能,实际上就是从结果集中显示第1至100条记录作为第1页,显示第101至200条记录作为第2页,以此类推

  • 分页实际上就是从结果集中“截取”出第M至N条记录。这个查询可以通过LIMIT <M>, <N>子句实现

  • 起始索引从0开始

  • 每页显示内容速算:LIMIT (PAGE-1)*SIZE, SIZE

  • 示例:

# 按employee_id排序,取出前5位员姓名
mysql> select employee_id, name from employees
    -> order by employee_id
    -> limit 0, 5;
+-------------+-----------+
| employee_id | name      |
+-------------+-----------+
|           1 | 梁伟      |
|           2 | 郭岩      |
|           3 | 李玉英    |
|           4 | 张健      |
|           5 | 郑静      |
+-------------+-----------+
5 rows in set (0.00 sec)


# 按employee_id排序,取出前15至20号员姓名
mysql> select employee_id, name from employees
    -> order by employee_id
    -> limit 15, 5;
+-------------+--------+
| employee_id | name   |
+-------------+--------+
|          16 | 聂想   |
|          17 | 陈阳   |
|          18 | 戴璐   |
|          19 | 陈斌   |
|          20 | 蒋红   |
+-------------+--------+
5 rows in set (0.00 sec)

联合查询UNION

  • 作用:将多条select语句的结果,合并到一起,称之为联合操作。
  • 语法:( ) UNION ( )
  • 要求查询时,多个select语句的检索到的字段数量必须一致
  • 每一条记录的各字段类型和顺序最好是一致的
  • UNION关键字默认去重,可以使用UNION ALL包含重复项
mysql> (select 'yes') union (select 'yes');
+-----+
| yes |
+-----+
| yes |
+-----+
1 row in set (0.00 sec)


mysql> (select 'yes') union all (select 'yes');
+-----+
| yes |
+-----+
| yes |
| yes |
+-----+
2 rows in set (0.00 sec)
  • 例,某生产商有一张原材料表和一张商品表,需要把原材料价格和商品价格一起输出

  • 查询1972年前或2000年后出生的员工

# 普通方法
mysql> select name, birth_date from employees
    -> where year(birth_date)<1972 or year(birth_date)>2000;
+-----------+------------+
| name      | birth_date |
+-----------+------------+
| 梁伟      | 1971-08-19 |
| 张建平    | 1971-11-02 |
| 窦红梅    | 1971-09-09 |
| 温兰英    | 1971-08-14 |
| 朱文      | 1971-08-15 |
| 和林      | 1971-12-10 |
+-----------+------------+
6 rows in set (0.01 sec)


# 联合查询的方法
mysql> (
    -> select name, birth_date from employees
    ->   where year(birth_date)<1972
    -> )
    -> union
    -> (
    ->   select name, birth_date from employees
    ->   where year(birth_date)>2000
    -> );
+-----------+------------+
| name      | birth_date |
+-----------+------------+
| 梁伟      | 1971-08-19 |
| 张建平    | 1971-11-02 |
| 窦红梅    | 1971-09-09 |
| 温兰英    | 1971-08-14 |
| 朱文      | 1971-08-15 |
| 和林      | 1971-12-10 |
+-----------+------------+
6 rows in set (0.00 sec)