MySQL之数据库的内嵌函数和联合查询
MySQL之数据库的内嵌函数和联合查询
- 一.数据库的内嵌函数
- 1.1聚合函数
- 1.2日期函数
- 1.3字符串处理函数
- 1.4 数学函数
- 1.5其他常用的函数
- 二.联合查询
- 2.1笛卡尔积
- 2.2内连接
- 2.3外连接
- 2.4 自连接
- 2.5子查询
- 2.6合并查询
一.数据库的内嵌函数
1.1聚合函数
在MySQL中有着一类聚合函数来方便我们完成数据的各自统计工作。
- COUNT([DISTINCT] expr)
返回查询到的数据的数量
//表中一共有几条记录
mysql> select count(*) from exam;
+----------+
| count(*) |
+----------+
| 7 |
+----------+
1 row in set (0.00 sec)//表中math列有几条记录
mysql> select count(math) from exam;
+-------------+
| count(math) |
+-------------+
| 7 |
+-------------+
1 row in set (0.00 sec)
- SUM([DISTINCT] expr)
返回查询到的数据的 总和,不是数字没有意义
//表中math列的总和
mysql> select sum(math) from exam;
+-----------+
| sum(math) |
+-----------+
| 837 |
+-----------+
1 row in set (0.00 sec)//表中math+chinese+english三列的总和
mysql> select sum(math+chinese+english) from exam;
+---------------------------+
| sum(math+chinese+english) |
+---------------------------+
| 1740 |
+---------------------------+
1 row in set (0.00 sec)
- AVG([DISTINCT] expr)
返回查询到的数据的 平均值,不是数字没有意义
//英语成绩的平均值
mysql> select avg(english) from exam;
+--------------------+
| avg(english) |
+--------------------+
| 62.285714285714285 |
+--------------------+
1 row in set (0.01 sec)//总成绩的平均值
mysql> select avg(english+math+chinese) from exam;
+---------------------------+
| avg(english+math+chinese) |
+---------------------------+
| 248.57142857142858 |
+---------------------------+
1 row in set (0.00 sec)
- MAX([DISTINCT] expr)
返回查询到的数据的 最大值,不是数字没有意义
//总成绩最高
mysql> select max(english+math+chinese) from exam;
+---------------------------+
| max(english+math+chinese) |
+---------------------------+
| 276 |
+---------------------------+
1 row in set (0.00 sec)
- MIN([DISTINCT] expr)
返回查询到的数据的 最小值,不是数字没有意义
//总成绩最低
mysql> select min(english+math+chinese) from exam;
+---------------------------+
| min(english+math+chinese) |
+---------------------------+
| 230 |
+---------------------------+
1 row in set (0.00 sec)
1.2日期函数
函数 | 说明 |
---|---|
CURDATE() | 返回当前日期,同义词 CURRENT_DATE , CURRENT_DATE() |
CURTIME() | 返回当前时间,同义词 CURRENT_TIME , CURRENT_TIME([fsp]) |
NOW() | 返回当前日期和时间,同义词CURRENT_TIMESTAMP,CURRENT_TIMESTAMP() |
DATE(data) | 提取date或者datetime中的日期部分 |
ADDDATE(date,INTERVAL expr unit) | 向日期指中添加时间值(间隔),同义词DATE_ADD() |
SUBDATE(date,INTERVAL expr unit) | 向日期中减去时间值(间隔),同义词DATE_SUB() |
DATEDIFF(expr1,expr2) | 两个日期的差,以天为单位,expr1 - expr2 |
日期函数都是我们一眼就能理解的所以我们就不做多演示了
1.3字符串处理函数
函数 | 说明 |
---|---|
CHAR_LENGTH(str) | 返回给定字符串的长度,同义词 CHARACTER_LENGTH() |
LENGTH(str) | 返回给定字符串的字节数,与当前使⽤的字符编码集有关 |
CONCAT(str1,str2,…) | 返回拼接后的字符串 |
CONCAT_WS(separator,str1,str2,…) | 返回拼接后带分隔符的字符串 |
LCASE(str) | 将给定字符串转换成小写,同义词 LOWER() |
UCASE(str) | 将给定字符串转换成大写,同义词 UPPER() |
HEX(str), HEX(N) | 对于字符串参数str, HEX()返回str的十六进制字符串表示形式,对于数字参数N, HEX()返回⼀个十六进制字符串表示形式 |
INSTR(str,substr) | 返回substring第一次出现的索引 |
INSERT(str,pos,len,newstr) | 在指定位置插入子字符串,最多不超过指定的字符数 |
SUBSTR(str,pos) ,SUBSTR(str FROM pos FOR len) | 返回指定的子字符串,同义词 SUBSTRING(str,pos) ,SUBSTRING(str FROM pos FOR len) |
REPLACE(str,from_str,to_str) | 把字符串str中所有的from_str替换为to_str,区分大小写 |
STRCMP(expr1,expr2) | 逐个字符比较两个字符串,返回 -1, 0 , 1 |
LEFT(str,len) ,RIGHT(str,len) | 返回字符串str中最左/最右边的len个字符 |
LTRIM(str) , RTRIM(str) ,TRIM(str) | 删除给定字符串的前导、末尾、前导和末尾的空格 |
TRIM([{LEADING / TRAILING / BOTH } remstr FROM str) | 删除给定符串的前导、末尾或前导和末尾的指定字符串 |
字符串处理函数很多,我们就挑其中一些不好理解的来给大家演示一下
#length(str),根据字符集返回字节数
mysql> select name,length(name) from exam;#这是utf8的所以一个字符占三个字节
+-----------+--------------+
| name | length(name) |
+-----------+--------------+
| 唐三藏 | 9 |
| 孙悟空 | 9 |
| 猪悟能 | 9 |
| 曹孟德 | 9 |
| 刘⽞德 | 9 |
| 孙权 | 6 |
| 宋公明 | 9 |
+-----------+--------------+
7 rows in set (0.00 sec)#hex(str | sum)将字符串或者数字转为16进制
mysql> select id,hex(id),name,hex(name) from exam;
+------+---------+-----------+--------------------+
| id | hex(id) | name | hex(name) |
+------+---------+-----------+--------------------+
| 1 | 1 | 唐三藏 | E59490E4B889E8978F |
| 2 | 2 | 孙悟空 | E5AD99E6829FE7A9BA |
| 3 | 3 | 猪悟能 | E78CAAE6829FE883BD |
| 4 | 4 | 曹孟德 | E69BB9E5AD9FE5BEB7 |
| 5 | 5 | 刘⽞德 | E58898E2BD9EE5BEB7 |
| 6 | 6 | 孙权 | E5AD99E69D83 |
| 7 | 7 | 宋公明 | E5AE8BE585ACE6988E |
+------+---------+-----------+--------------------+
7 rows in set (0.00 sec)#instr(str,substr) 返回substr在str中第一次出现的索引
mysql> select name,instr(name,'孙') from exam;\
+-----------+-------------------+
| name | instr(name,'孙') |
+-----------+-------------------+
| 唐三藏 | 0 |
| 孙悟空 | 1 |
| 猪悟能 | 0 |
| 曹孟德 | 0 |
| 刘⽞德 | 0 |
| 孙权 | 1 |
| 宋公明 | 0 |
+-----------+-------------------+
7 rows in set (0.00 sec)#trim({LEADING / TRAILING / BOTH} str from ori_str) 删除给定符串的前导、末尾或前导和末尾的指定字符串
mysql> select trim(both 'xxx' from 'xxxworldxxx');
+-------------------------------------+
| trim(both 'xxx' from 'xxxworldxxx') |
+-------------------------------------+
| world |
+-------------------------------------+
1 row in set (0.00 sec)
1.4 数学函数
函数 | 说明 |
---|---|
ABS(X) | 返回X的绝对值 |
CEIL(X) | 返回不小于X的最小整数值,同义词是 CEILING(X) |
FLOOR(X) | 返回不大于X的最大整数值 |
CONV(N,from_base,to_base) | 不同进制之间的转换 |
FORMAT(X,D) | 将数字X格式化为“#,###,###”的格式。##',四舍五入到小数点后D位,并以字符串形式返回 |
RAND([N]) | 返回⼀个随机浮点值,取值范围 [0.0, 1.0) |
ROUND(X), ROUND(X,D) | 将参数X舍入到小数点后D位 |
CRC32(expr) | 计算指定字符串的循环冗余校验值并返回⼀个32位无符号整数 |
一样我们挑几个来演示
#ceil(x) 向上取整
mysql> select ceil(3.14),ceil(3.9),ceil(-3.1),ceil(-3.9);
+------------+-----------+------------+------------+
| ceil(3.14) | ceil(3.9) | ceil(-3.1) | ceil(-3.9) |
+------------+-----------+------------+------------+
| 4 | 4 | -3 | -3 |
+------------+-----------+------------+------------+
1 row in set (0.00 sec)#floor(x) 向下取整
mysql> select floor(3.14),floor(3.9),floor(-3.1),floor(-3.9);
+-------------+------------+-------------+-------------+
| floor(3.14) | floor(3.9) | floor(-3.1) | floor(-3.9) |
+-------------+------------+-------------+-------------+
| 3 | 3 | -4 | -4 |
+-------------+------------+-------------+-------------+
1 row in set (0.00 sec)
我们想要了理解向上和向下取整分别是什么意思我们需要把数轴旋转90度让其变成竖直的样子。
#format(x,D) 把数字转换为’x.xxx.xxx.xxxx...'的形式,小数点四舍五入保留D位并且是以字符串的形式
mysql> select format(1564679.1566,3);
+------------------------+
| format(1564679.1566,3) |
+------------------------+
| 1,564,679.157 |
+------------------------+
1 row in set (0.00 sec)#crc32(x) 将字符串转换为一个32位无符号整型
mysql> select crc32('hello'),crc32('world');
+----------------+----------------+
| crc32('hello') | crc32('world') |
+----------------+----------------+
| 907060870 | 980881731 |
+----------------+----------------+
1 row in set (0.00 sec)
1.5其他常用的函数
函数 | 说明 |
---|---|
version() | 显示当前数据库版本 |
database() | 显示当前正在使用的数据库 |
user() | 显示当前用户 |
md5(str) | 对一个字符串进行md5摘要,摘要后得到⼀个32位字符串 |
ifnull(val1, val2) | 如果val1为NULL,返回val2,否则返回 val1 |
这五个函数除了md5需要讲一下之外其他的函数我们直接看说明就知道是什么作用了,所以我们只需要讲讲md5的作用。
我们知道数据库是用来存储数据的例如用户的账号密码,但是数据库也是很好入侵的如果我们的密码就那么明晃晃的存储在数据库中黑客一入侵就可以把存储的账号密码全部盗走了所以我们需要对密码进行加密而md5函数就是一个加密函数它可以把一个字符串通过特殊的算法转换为一串32位的字符串。
mysql> select md5('123456789');
+----------------------------------+
| md5('123456789') |
+----------------------------------+
| 25f9e794323b453885f5181f1b624d0b |
+----------------------------------+
1 row in set (0.00 sec)
二.联合查询
2.1笛卡尔积
在掌握了基础的查询方法后我们可以发现我们刚刚的例子都是单表查询但是在实际应用中有时候我们是需要从多张表中查询出一条数据的完整消息的,所以这时候我们就需要用到多表查询也就是联合查询。
想进行多表查询的话我们就需要将多张表组合在一起这个组合的过程在MySQL中叫做取笛卡尔积,这个概念大家可能在数学学习中听到过指的是将两个集合构成有序二元组也叫做两个集合的笛卡尔积。MySQL中表就代替了集合,所以是给表取笛卡尔积。
mysql> select * from exam,emp;
+------+-----------+---------+------+---------+----+-----------+--------+------------+
| id | name | chinese | math | english | id | name | role | salary |
+------+-----------+---------+------+---------+----+-----------+--------+------------+
| 7 | 宋公明 | 75 | 125 | 30 | 1 | 马云 | 老板 | 1500000.00 |
| 6 | 孙权 | 70 | 103 | 78 | 1 | 马云 | 老板 | 1500000.00 |
| 5 | 刘⽞德 | 55 | 145 | 45 | 1 | 马云 | 老板 | 1500000.00 |
| 4 | 曹孟德 | 82 | 100 | 60 | 1 | 马云 | 老板 | 1500000.00 |
| 3 | 猪悟能 | 88 | 98 | 90 | 1 | 马云 | 老板 | 1500000.00 |
| 2 | 孙悟空 | 30 | 138 | 77 | 1 | 马云 | 老板 | 1500000.00 |
| 1 | 唐三藏 | 67 | 128 | 56 | 1 | 马云 | 老板 | 1500000.00 |
| 7 | 宋公明 | 75 | 125 | 30 | 2 | 马化腾 | 老板 | 1300000.00 |
| 6 | 孙权 | 70 | 103 | 78 | 2 | 马化腾 | 老板 | 1300000.00 |
| 5 | 刘⽞德 | 55 | 145 | 45 | 2 | 马化腾 | 老板 | 1300000.00 |
| 4 | 曹孟德 | 82 | 100 | 60 | 2 | 马化腾 | 老板 | 1300000.00 |
| 3 | 猪悟能 | 88 | 98 | 90 | 2 | 马化腾 | 老板 | 1300000.00 |
| 2 | 孙悟空 | 30 | 138 | 77 | 2 | 马化腾 | 老板 | 1300000.00 |
| 1 | 唐三藏 | 67 | 128 | 56 | 2 | 马化腾 | 老板 | 1300000.00 |
| 7 | 宋公明 | 75 | 125 | 30 | 3 | 张三 | 经理 | 13000.00 |
| 6 | 孙权 | 70 | 103 | 78 | 3 | 张三 | 经理 | 13000.00 |
| 5 | 刘⽞德 | 55 | 145 | 45 | 3 | 张三 | 经理 | 13000.00 |
| 4 | 曹孟德 | 82 | 100 | 60 | 3 | 张三 | 经理 | 13000.00 |
| 3 | 猪悟能 | 88 | 98 | 90 | 3 | 张三 | 经理 | 13000.00 |
| 2 | 孙悟空 | 30 | 138 | 77 | 3 | 张三 | 经理 | 13000.00 |
| 1 | 唐三藏 | 67 | 128 | 56 | 3 | 张三 | 经理 | 13000.00 |
| 7 | 宋公明 | 75 | 125 | 30 | 4 | 赵四 | 经理 | 11000.00 |
| 6 | 孙权 | 70 | 103 | 78 | 4 | 赵四 | 经理 | 11000.00 |
| 5 | 刘⽞德 | 55 | 145 | 45 | 4 | 赵四 | 经理 | 11000.00 |
| 4 | 曹孟德 | 82 | 100 | 60 | 4 | 赵四 | 经理 | 11000.00 |
| 3 | 猪悟能 | 88 | 98 | 90 | 4 | 赵四 | 经理 | 11000.00 |
| 2 | 孙悟空 | 30 | 138 | 77 | 4 | 赵四 | 经理 | 11000.00 |
| 1 | 唐三藏 | 67 | 128 | 56 | 4 | 赵四 | 经理 | 11000.00 |
| 7 | 宋公明 | 75 | 125 | 30 | 5 | 王五 | 员工 | 5000.00 |
| 6 | 孙权 | 70 | 103 | 78 | 5 | 王五 | 员工 | 5000.00 |
| 5 | 刘⽞德 | 55 | 145 | 45 | 5 | 王五 | 员工 | 5000.00 |
| 4 | 曹孟德 | 82 | 100 | 60 | 5 | 王五 | 员工 | 5000.00 |
| 3 | 猪悟能 | 88 | 98 | 90 | 5 | 王五 | 员工 | 5000.00 |
| 2 | 孙悟空 | 30 | 138 | 77 | 5 | 王五 | 员工 | 5000.00 |
| 1 | 唐三藏 | 67 | 128 | 56 | 5 | 王五 | 员工 | 5000.00 |
| 7 | 宋公明 | 75 | 125 | 30 | 6 | 田七 | 员工 | 6000.00 |
| 6 | 孙权 | 70 | 103 | 78 | 6 | 田七 | 员工 | 6000.00 |
| 5 | 刘⽞德 | 55 | 145 | 45 | 6 | 田七 | 员工 | 6000.00 |
| 4 | 曹孟德 | 82 | 100 | 60 | 6 | 田七 | 员工 | 6000.00 |
| 3 | 猪悟能 | 88 | 98 | 90 | 6 | 田七 | 员工 | 6000.00 |
| 2 | 孙悟空 | 30 | 138 | 77 | 6 | 田七 | 员工 | 6000.00 |
| 1 | 唐三藏 | 67 | 128 | 56 | 6 | 田七 | 员工 | 6000.00 |
| 7 | 宋公明 | 75 | 125 | 30 | 7 | 路人甲 | 保安 | 2000.00 |
| 6 | 孙权 | 70 | 103 | 78 | 7 | 路人甲 | 保安 | 2000.00 |
| 5 | 刘⽞德 | 55 | 145 | 45 | 7 | 路人甲 | 保安 | 2000.00 |
| 4 | 曹孟德 | 82 | 100 | 60 | 7 | 路人甲 | 保安 | 2000.00 |
| 3 | 猪悟能 | 88 | 98 | 90 | 7 | 路人甲 | 保安 | 2000.00 |
| 2 | 孙悟空 | 30 | 138 | 77 | 7 | 路人甲 | 保安 | 2000.00 |
| 1 | 唐三藏 | 67 | 128 | 56 | 7 | 路人甲 | 保安 | 2000.00 |
| 7 | 宋公明 | 75 | 125 | 30 | 8 | 路人乙 | 保安 | 2000.00 |
| 6 | 孙权 | 70 | 103 | 78 | 8 | 路人乙 | 保安 | 2000.00 |
| 5 | 刘⽞德 | 55 | 145 | 45 | 8 | 路人乙 | 保安 | 2000.00 |
| 4 | 曹孟德 | 82 | 100 | 60 | 8 | 路人乙 | 保安 | 2000.00 |
| 3 | 猪悟能 | 88 | 98 | 90 | 8 | 路人乙 | 保安 | 2000.00 |
| 2 | 孙悟空 | 30 | 138 | 77 | 8 | 路人乙 | 保安 | 2000.00 |
| 1 | 唐三藏 | 67 | 128 | 56 | 8 | 路人乙 | 保安 | 2000.00 |
+------+-----------+---------+------+---------+----+-----------+--------+------------+
56 rows in set (0.00 sec)
从这两个表的笛卡尔积我们就能发现仅仅两张表的笛卡尔积就已经很繁琐了更别提三张四张甚至更多了所以我们在取笛卡尔积的时候一定进行条件判断来去除哪些无用的重复的数据从而减少行数来减轻字节的负担。
所以我现在用一个更具体的例子来给大家完成一个完整的联合查询
//两个表的笛卡尔积
mysql> select * from student,class;
+----+--------------+--------+------+--------+-------------+----------+----+--------------+
| id | name | sno | age | gender | enroll_date | class_id | id | name |
+----+--------------+--------+------+--------+-------------+----------+----+--------------+
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 | 3 | 前端001班 |
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 | 2 | C++001班 |
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 | 1 | Java001班 |
| 2 | 孙悟空 | 100002 | 18 | 1 | 1986-09-01 | 1 | 3 | 前端001班 |
| 2 | 孙悟空 | 100002 | 18 | 1 | 1986-09-01 | 1 | 2 | C++001班 |
| 2 | 孙悟空 | 100002 | 18 | 1 | 1986-09-01 | 1 | 1 | Java001班 |
| 3 | 猪悟能 | 100003 | 18 | 1 | 1986-09-01 | 1 | 3 | 前端001班 |
| 3 | 猪悟能 | 100003 | 18 | 1 | 1986-09-01 | 1 | 2 | C++001班 |
| 3 | 猪悟能 | 100003 | 18 | 1 | 1986-09-01 | 1 | 1 | Java001班 |
| 4 | 沙悟净 | 100004 | 18 | 1 | 1986-09-01 | 1 | 3 | 前端001班 |
| 4 | 沙悟净 | 100004 | 18 | 1 | 1986-09-01 | 1 | 2 | C++001班 |
| 4 | 沙悟净 | 100004 | 18 | 1 | 1986-09-01 | 1 | 1 | Java001班 |
| 5 | 宋江 | 200001 | 18 | 1 | 2000-09-01 | 2 | 3 | 前端001班 |
| 5 | 宋江 | 200001 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
| 5 | 宋江 | 200001 | 18 | 1 | 2000-09-01 | 2 | 1 | Java001班 |
| 6 | 武松 | 200002 | 18 | 1 | 2000-09-01 | 2 | 3 | 前端001班 |
| 6 | 武松 | 200002 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
| 6 | 武松 | 200002 | 18 | 1 | 2000-09-01 | 2 | 1 | Java001班 |
| 7 | 李逹 | 200003 | 18 | 1 | 2000-09-01 | 2 | 3 | 前端001班 |
| 7 | 李逹 | 200003 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
| 7 | 李逹 | 200003 | 18 | 1 | 2000-09-01 | 2 | 1 | Java001班 |
| 8 | 不想毕业 | 200004 | 18 | 1 | 2000-09-01 | 2 | 3 | 前端001班 |
| 8 | 不想毕业 | 200004 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
| 8 | 不想毕业 | 200004 | 18 | 1 | 2000-09-01 | 2 | 1 | Java001班 |
+----+--------------+--------+------+--------+-------------+----------+----+--------------+
24 rows in set (0.00 sec)//增加条件判断,通过student中的class_id和class中的id
mysql> select * from student,class where student.class_id = class.id;
+----+--------------+--------+------+--------+-------------+----------+----+------------+
| id | name | sno | age | gender | enroll_date | class_id | id | name |
+----+--------------+--------+------+--------+-------------+----------+----+------------+
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 | 1 | Java001班 |
| 2 | 孙悟空 | 100002 | 18 | 1 | 1986-09-01 | 1 | 1 | Java001班 |
| 3 | 猪悟能 | 100003 | 18 | 1 | 1986-09-01 | 1 | 1 | Java001班 |
| 4 | 沙悟净 | 100004 | 18 | 1 | 1986-09-01 | 1 | 1 | Java001班 |
| 5 | 宋江 | 200001 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
| 6 | 武松 | 200002 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
| 7 | 李逹 | 200003 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
| 8 | 不想毕业 | 200004 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
+----+--------------+--------+------+--------+-------------+----------+----+------------+
8 rows in set (0.00 sec)//再增加条件判断
mysql> select * from student,class where student.class_id = class.id and student.name = '宋江';
+----+--------+--------+------+--------+-------------+----------+----+-----------+
| id | name | sno | age | gender | enroll_date | class_id | id | name |
+----+--------+--------+------+--------+-------------+----------+----+-----------+
| 5 | 宋江 | 200001 | 18 | 1 | 2000-09-01 | 2 | 2 | C++001班 |
+----+--------+--------+------+--------+-------------+----------+----+-----------+
1 row in set (0.00 sec)//修改查询字段,可以给表取别名来方便编写
mysql> select s.id,s.name,s.sno,s.age,s.gender,s.enroll_date,s.class_id,c.name from student s,class c where s.class_id = c.id and s.name = '宋江';
+----+--------+--------+------+--------+-------------+----------+-----------+
| id | name | sno | age | gender | enroll_date | class_id | name |
+----+--------+--------+------+--------+-------------+----------+-----------+
| 5 | 宋江 | 200001 | 18 | 1 | 2000-09-01 | 2 | C++001班 |
+----+--------+--------+------+--------+-------------+----------+-----------+
1 row in set (0.00 sec)
2.2内连接
select
{col_name | expr} ,... #字段
from
tal_name1 name1, #表1 别名1
tal_name2 name2 #表2 别名2
where where_condition #where 判断条件
and other_condition; #and 其他条件select
{col_name | expr} ,... #字段
from
tal_name1 name1 #表1 别名1
[inner] join #内连接
tal_name2 name2 #表2 别名2
on connect_condition #on 连接条件
where other_condition; #where 其他条件
这两种方法都是内连接所以大家可以发现我们在上面获得笛卡尔积再增加判断条件的时候就是在把这两张表进行内连接。既然现在知道了是将这两个表进行内连接那么大家以后就把不要用上面那种方法了用下面这种可以显式说明是内连接的。
2.3外连接
外连接分为左外连接,右外连接以及全外连接但是MySQL不支持全外连接。
- 左外连接:返回左表的所有记录和右表中匹配的记录。如果右表中没有匹配的记录,则结果集对应字段会显式为NULL。
- 右外连接:与左外连接相反,返回右表的所有记录和左表中匹配的记录。如果左表中没有匹配的记录,则结果集中对应字段会显式为NULL。
- 全外连接:结合了左外连接和右外连接的特点,返回左右表中的所有记录。如果某一边表中没有匹配的记录,则结果集中对应字段会显示为NULL。
#左外连接,表1完全显⽰
select 字段名 from 表名1 left join 表名2 on 连接条件;
#右外连接,表2完全显⽰
select 字段 from 表名1 right join 表名2 on 连接条件;
我们来各自举个例子方便大家理解
#左外连接
#列出每个学生的每门课程的考试成绩
mysql> select s.id,s.name,s.sno,s.age,sc.* from student s left join score sc on s.id = sc.student_id;
+----+--------------+--------+------+------+-------+------------+-----------+
| id | name | sno | age | id | score | student_id | course_id |
+----+--------------+--------+------+------+-------+------------+-----------+
| 1 | 唐三藏 | 100001 | 18 | 1 | 70.5 | 1 | 1 |
| 1 | 唐三藏 | 100001 | 18 | 2 | 98.5 | 1 | 3 |
| 1 | 唐三藏 | 100001 | 18 | 3 | 33 | 1 | 5 |
| 1 | 唐三藏 | 100001 | 18 | 4 | 98 | 1 | 6 |
| 2 | 孙悟空 | 100002 | 18 | 5 | 60 | 2 | 1 |
| 2 | 孙悟空 | 100002 | 18 | 6 | 59.5 | 2 | 5 |
| 3 | 猪悟能 | 100003 | 18 | 7 | 33 | 3 | 1 |
| 3 | 猪悟能 | 100003 | 18 | 8 | 68 | 3 | 3 |
| 3 | 猪悟能 | 100003 | 18 | 9 | 99 | 3 | 5 |
| 4 | 沙悟净 | 100004 | 18 | 10 | 67 | 4 | 1 |
| 4 | 沙悟净 | 100004 | 18 | 11 | 23 | 4 | 3 |
| 4 | 沙悟净 | 100004 | 18 | 12 | 56 | 4 | 5 |
| 4 | 沙悟净 | 100004 | 18 | 13 | 72 | 4 | 6 |
| 5 | 宋江 | 200001 | 18 | 14 | 81 | 5 | 1 |
| 5 | 宋江 | 200001 | 18 | 15 | 37 | 5 | 5 |
| 6 | 武松 | 200002 | 18 | 16 | 56 | 6 | 2 |
| 6 | 武松 | 200002 | 18 | 17 | 43 | 6 | 4 |
| 6 | 武松 | 200002 | 18 | 18 | 79 | 6 | 6 |
| 7 | 李逹 | 200003 | 18 | 19 | 80 | 7 | 2 |
| 7 | 李逹 | 200003 | 18 | 20 | 92 | 7 | 6 |
| 8 | 不想毕业 | 200004 | 18 | NULL | NULL | NULL | NULL |
+----+--------------+--------+------+------+-------+------------+-----------+
21 rows in set (0.00 sec)
可以发现当student为左表时即使左表的某行在右表中没有数据但是也会显示出来只不过右表的数据为空而已,具体来说就是最后一行。
#右外连接
#查询没有学生的班级
mysql> select s.id,s.name,s.class_id,cl.* from student s right join class cl on s.class_id = cl.id;
+------+--------------+----------+----+--------------+
| id | name | class_id | id | name |
+------+--------------+----------+----+--------------+
| 1 | 唐三藏 | 1 | 1 | Java001班 |
| 2 | 孙悟空 | 1 | 1 | Java001班 |
| 3 | 猪悟能 | 1 | 1 | Java001班 |
| 4 | 沙悟净 | 1 | 1 | Java001班 |
| 5 | 宋江 | 2 | 2 | C++001班 |
| 6 | 武松 | 2 | 2 | C++001班 |
| 7 | 李逹 | 2 | 2 | C++001班 |
| 8 | 不想毕业 | 2 | 2 | C++001班 |
| NULL | NULL | NULL | 3 | 前端001班 |
+------+--------------+----------+----+--------------+
9 rows in set (0.00 sec)
右外连接则与左外连接相反,它会完全展示出右表的数据即使右表对应行在左表中没有数据。
2.4 自连接
内外连接都说完了就到了自连接了它也很好理解就是自己和自己取笛卡尔积再进行条件判断。可以用于完成表中行与行的对比但是在使用时必须给每个表取别名。
#显⽰所有"MySQL"成绩⽐"JAVA"成绩⾼的成绩信息#1.获取java和MySQL的课程代码
mysql> select * from course where name = 'Java' or name = 'MySQL';
+----+-------+
| id | name |
+----+-------+
| 1 | Java |
| 3 | MySQL |
+----+-------+
2 rows in set (0.00 sec)#2.获取MySQL成绩比java好的信息
mysql> select s1.* from score s1, score s2 where s1.student_id = s2.student_id -> and s1.course_id = 3 and s2.course_id = 1 and s1.score > s2.score;
+----+-------+------------+-----------+
| id | score | student_id | course_id |
+----+-------+------------+-----------+
| 2 | 98.5 | 1 | 3 |
| 8 | 68 | 3 | 3 |
+----+-------+------------+-----------+
2 rows in set (0.00 sec)#也可以将其组合在一起
mysql> select s1.* from-> score s1, -> score s2, -> course c1,-> course c2-> where-> s1.student_id = s2.student_id-> and-> s1.course_id = c1.id-> and-> s2.course_id = c2.id -> and-> s1.score > s2.score-> and-> c1.`name` = 'MySQL'-> and-> c2.`name` = 'Java';
+----+-------+------------+-----------+
| id | score | student_id | course_id |
+----+-------+------------+-----------+
| 2 | 98.5 | 1 | 3 |
| 8 | 68 | 3 | 3 |
+----+-------+------------+-----------+
2 rows in set (0.01 sec)
2.5子查询
子查询就是将一个select的结果当作另外一个select的条件,也被叫做嵌套查询。一样我们还是开始举例。
同时子查询也被分为三种:单行子查询,多行子查询,多列子查询
#单行子查询
#查询不想毕业的同班同学
mysql> select * from student where class_id = (select class_id from student where name = '不想毕业');
+----+--------------+--------+------+--------+-------------+----------+
| id | name | sno | age | gender | enroll_date | class_id |
+----+--------------+--------+------+--------+-------------+----------+
| 5 | 宋江 | 200001 | 18 | 1 | 2000-09-01 | 2 |
| 6 | 武松 | 200002 | 18 | 1 | 2000-09-01 | 2 |
| 7 | 李逹 | 200003 | 18 | 1 | 2000-09-01 | 2 |
| 8 | 不想毕业 | 200004 | 18 | 1 | 2000-09-01 | 2 |
+----+--------------+--------+------+--------+-------------+----------+
4 rows in set (0.01 sec)#多行子查询
#查询课程Java或者MySQL的成绩信息
mysql> select * from score where course_id in (select id from course where name = 'Java' or name = 'MySQL');
+----+-------+------------+-----------+
| id | score | student_id | course_id |
+----+-------+------------+-----------+
| 1 | 70.5 | 1 | 1 |
| 5 | 60 | 2 | 1 |
| 7 | 33 | 3 | 1 |
| 10 | 67 | 4 | 1 |
| 14 | 81 | 5 | 1 |
| 2 | 98.5 | 1 | 3 |
| 8 | 68 | 3 | 3 |
| 11 | 23 | 4 | 3 |
+----+-------+------------+-----------+
8 rows in set (0.00 sec)#多列子查询
#插入重复成绩
mysql> insert into score(score, student_id, course_id) values-> (70.5, 1, 1),(98.5, 1, 3),(60, 2, 1);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0#查找重复的成绩
mysql> SELECT * FROM score WHERE (score, student_id, course_id ) IN ( -> SELECT score, student_id,-> course_id FROM score GROUP BY score, student_id, course_id HAVING-> count( 0 ) > 1);
+----+-------+------------+-----------+
| id | score | student_id | course_id |
+----+-------+------------+-----------+
| 1 | 70.5 | 1 | 1 |
| 2 | 98.5 | 1 | 3 |
| 5 | 60 | 2 | 1 |
| 21 | 70.5 | 1 | 1 |
| 22 | 98.5 | 1 | 3 |
| 23 | 60 | 2 | 1 |
+----+-------+------------+-----------+
6 rows in set (0.00 sec)
之前我们说过MySQL中一切都是表所以select的结果不光可以当作判断条件来完成子查询也可以当作from后的表来完成子查询,这是因为select的结果就是一张临时表。
2.6合并查询
当我们想要合并多个select的结果,我们就可以使用集合操作符union和union all。
union:该操作符用于取得两个结果集的并集,当使用该操作符时会自动去除结果集中的重复行。
union all:该操作符用于取得两个结果集的并集,当使用该操作符时不会去除结果集中的重复行。
mysql> select * from student1;
+----+-----------+--------+------+--------+-------------+----------+
| id | name | sno | age | gender | enroll_date | class_id |
+----+-----------+--------+------+--------+-------------+----------+
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 |
| 2 | 刘备 | 300001 | 18 | 1 | 1993-09-01 | 3 |
| 3 | 张⻜ | 300002 | 18 | 1 | 1993-09-01 | 3 |
| 4 | 关⽻ | 300003 | 18 | 1 | 1993-09-01 | 3 |
+----+-----------+--------+------+--------+-------------+----------+
4 rows in set (0.00 sec)mysql> select * from student;
+----+--------------+--------+------+--------+-------------+----------+
| id | name | sno | age | gender | enroll_date | class_id |
+----+--------------+--------+------+--------+-------------+----------+
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 |
| 2 | 孙悟空 | 100002 | 18 | 1 | 1986-09-01 | 1 |
| 3 | 猪悟能 | 100003 | 18 | 1 | 1986-09-01 | 1 |
| 4 | 沙悟净 | 100004 | 18 | 1 | 1986-09-01 | 1 |
| 5 | 宋江 | 200001 | 18 | 1 | 2000-09-01 | 2 |
| 6 | 武松 | 200002 | 18 | 1 | 2000-09-01 | 2 |
| 7 | 李逹 | 200003 | 18 | 1 | 2000-09-01 | 2 |
| 8 | 不想毕业 | 200004 | 18 | 1 | 2000-09-01 | 2 |
+----+--------------+--------+------+--------+-------------+----------+
8 rows in set (0.00 sec)mysql> select * from student where id < 3 union select * from student1;
+----+-----------+--------+------+--------+-------------+----------+
| id | name | sno | age | gender | enroll_date | class_id |
+----+-----------+--------+------+--------+-------------+----------+
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 |
| 2 | 孙悟空 | 100002 | 18 | 1 | 1986-09-01 | 1 |
| 2 | 刘备 | 300001 | 18 | 1 | 1993-09-01 | 3 |
| 3 | 张⻜ | 300002 | 18 | 1 | 1993-09-01 | 3 |
| 4 | 关⽻ | 300003 | 18 | 1 | 1993-09-01 | 3 |
+----+-----------+--------+------+--------+-------------+----------+
5 rows in set (0.00 sec)mysql> select * from student where id < 3 union all select * from student1;
+----+-----------+--------+------+--------+-------------+----------+
| id | name | sno | age | gender | enroll_date | class_id |
+----+-----------+--------+------+--------+-------------+----------+
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 |
| 2 | 孙悟空 | 100002 | 18 | 1 | 1986-09-01 | 1 |
| 1 | 唐三藏 | 100001 | 18 | 1 | 1986-09-01 | 1 |
| 2 | 刘备 | 300001 | 18 | 1 | 1993-09-01 | 3 |
| 3 | 张⻜ | 300002 | 18 | 1 | 1993-09-01 | 3 |
| 4 | 关⽻ | 300003 | 18 | 1 | 1993-09-01 | 3 |
+----+-----------+--------+------+--------+-------------+----------+
6 rows in set (0.00 sec)