mysql的多表查询
对于mysql在生活中的应用,使用的最多的就是查,你的每次浏览都可能是对mysql数据的一次查询,
因此mysql数据查询的方式非常多样化,尤其是对于多表联合查询。
现在给出三张表,后面的操作都是在这三张表上进行的。
表一:学生信息表(student_info)
mysql> select * from student_info; +----+-----------+------+ | id | name | sex | +----+-----------+------+ | 1 | 科比 | 男 | | 2 | 毛线 | 女 | | 3 | 黄鱼 | 男 | | 4 | 子栋 | 男 | | 5 | 子豪 | 女 | | 6 | 小鸟 | 男 | | 7 | 星爷 | 男 | | 8 | 戴鹏 | 男 | | 9 | 秦子琪 | 女 | +----+-----------+------+ 9 rows in set (0.00 sec)
表二:学生地址表(student_addr)
mysql> select * from student_addr; +--------+--------------+ | name | addr | +--------+--------------+ | 科比 | 湖北罗田 | | 小鸟 | 湖北襄阳 | | 子豪 | 江苏扬州 | | 毛线 | 湖北孝感 | | 子栋 | 湖北洪湖 | | 黄鱼 | 湖北罗田 | +--------+--------------+ 6 rows in set (0.00 sec)
表二:学生成绩表(student_score)
mysql> select * from student_score; +--------+-------+-------+--------+ | name | MYSQL | LIUNX | python | +--------+-------+-------+--------+ | 科比 | 56 | 87 | 74 | | 毛线 | 87 | 95 | 78 | | 小鸟 | 60 | 78 | 87 | | 子豪 | 54 | 67 | 57 | | 子栋 | 90 | 95 | 94 | | 黄鱼 | 78 | 69 | 90 | | 星爷 | 24 | 45 | 42 | +--------+-------+-------+--------+ 7 rows in set (0.00 sec)
1.使用select语句直接多表查询(取交集)
语法:SELECT 字段名 FROM 表1,表2......WHERE 表1.字段 = 表2.字段 AND 其它条件
两张表查询:
mysql> select student_info.id,student_info.name,student_info.sex,student_addr.addr -> from student_info,student_addr -> where student_info.name = student_addr.name;
mysql> select student_info.id,student_info.name,student_info.sex,student_addr.addr -> from student_info,student_addr -> where student_info.name = student_addr.name; +----+--------+------+--------------+ | id | name | sex | addr | +----+--------+------+--------------+ | 1 | 科比 | 男 | 湖北罗田 | | 2 | 毛线 | 女 | 湖北孝感 | | 3 | 黄鱼 | 男 | 湖北罗田 | | 4 | 子栋 | 男 | 湖北洪湖 | | 5 | 子豪 | 女 | 江苏扬州 | | 6 | 小鸟 | 男 | 湖北襄阳 | +----+--------+------+--------------+ 6 rows in set (0.00 sec) #结果取交集
三表查询:
mysql> select student_info.id,student_info.name,student_addr.addr,student_score.python -> from student_info,student_addr,student_score -> where student_info.name = student_addr.name and student_addr.name = student_score.name;
mysql> select student_info.id,student_info.name,student_addr.addr,student_score.python -> from student_info,student_addr,student_score -> where student_info.name = student_addr.name and student_addr.name = student_score.name; +----+--------+--------------+--------+ | id | name | addr | python | +----+--------+--------------+--------+ | 1 | 科比 | 湖北罗田 | 74 | | 2 | 毛线 | 湖北孝感 | 78 | | 3 | 黄鱼 | 湖北罗田 | 90 | | 4 | 子栋 | 湖北洪湖 | 94 | | 5 | 子豪 | 江苏扬州 | 57 | | 6 | 小鸟 | 湖北襄阳 | 87 | +----+--------+--------------+--------+ 6 rows in set (0.00 sec)
不管是几张表都可以用这种方式来进行查询,查询的结果取交集。
小技巧:表名太多太长,可以使用别名查询;
#使用别名 mysql> select a.id,a.name,a.sex,b.addr from student_info a,student_addr b -> where a.name = b.name;
mysql> select a.id,a.name,a.sex,b.addr from student_info a,student_addr b -> where a.name = b.name; +----+--------+------+--------------+ | id | name | sex | addr | +----+--------+------+--------------+ | 1 | 科比 | 男 | 湖北罗田 | | 2 | 毛线 | 女 | 湖北孝感 | | 3 | 黄鱼 | 男 | 湖北罗田 | | 4 | 子栋 | 男 | 湖北洪湖 | | 5 | 子豪 | 女 | 江苏扬州 | | 6 | 小鸟 | 男 | 湖北襄阳 | +----+--------+------+--------------+ 6 rows in set (0.12 sec)
2.合并多个结果集(union和union all)
在SQL语句中,可以通过union或union all将多个select语句的查询结果合并起来,二者的功能有类似之处,但是也有不同的地方。
在使用union或union all关键字将表合并输出地时候,查询结果必须具有相同的结构并且数据类型必须兼容,另外使用union或union all时两张表的字段数量也必须相同,否则会报错。
需要合并的表:
mysql> select * from student_addr; +--------+--------------+ | name | addr | +--------+--------------+ | 科比 | 湖北罗田 | | 小鸟 | 湖北襄阳 | | 子豪 | 江苏扬州 | | 毛线 | 湖北孝感 | | 子栋 | 湖北洪湖 | | 黄鱼 | 湖北罗田 | +--------+--------------+ 6 rows in set (0.00 sec)
mysql> select * from new_student_addr; +-----------+--------------+ | name | addr | +-----------+--------------+ | 小鸟 | 湖北襄阳 | | 子豪 | 江苏扬州 | | 毛线 | 湖北孝感 | | 子栋 | 湖北洪湖 | | 周杰 | 湖南常德 | | 魏武 | 河北保定 | | 王晨 | 山西晋城 | | 欧飞龙 | 浙江茂名 | +-----------+--------------+ 8 rows in set (0.00 sec)
union:利用该关键字可以将多个SELECT语句的查询结果合并输出,并删除重复行。
mysql> select * from student_addr union select * from new_student_addr; +-----------+--------------+ | name | addr | +-----------+--------------+ | 科比 | 湖北罗田 | | 小鸟 | 湖北襄阳 | | 子豪 | 江苏扬州 | | 毛线 | 湖北孝感 | | 子栋 | 湖北洪湖 | | 黄鱼 | 湖北罗田 | #没有完全重复的两条记录 | 周杰 | 湖南常德 | | 魏武 | 河北保定 | | 王晨 | 山西晋城 | | 欧飞龙 | 浙江茂名 | +-----------+--------------+ 10 rows in set (0.07 sec)
union all:利用该关键字可以将多个SELECCT语句的查询结果合并输出,但不会删除重复的行。
mysql> select * from student_addr union all select * from new_student_addr; +-----------+--------------+ | name | addr | +-----------+--------------+ | 科比 | 湖北罗田 | | 小鸟 | 湖北襄阳 | | 子豪 | 江苏扬州 | | 毛线 | 湖北孝感 | | 子栋 | 湖北洪湖 | | 黄鱼 | 湖北罗田 | | 小鸟 | 湖北襄阳 | | 子豪 | 江苏扬州 | | 毛线 | 湖北孝感 | | 子栋 | 湖北洪湖 | | 周杰 | 湖南常德 | | 魏武 | 河北保定 | | 王晨 | 山西晋城 | | 欧飞龙 | 浙江茂名 | +-----------+--------------+ 14 rows in set (0.00 sec)
3.左连接和右连接
左连接:以join左边的表为主
mysql> select student_info.id, student_info.name, student_info.sex, student_addr.addr -> from student_info left join student_addr on student_info.name = student_addr.name; +----+-----------+------+--------------+ | id | name | sex | addr | +----+-----------+------+--------------+ | 1 | 科比 | 男 | 湖北罗田 | | 2 | 毛线 | 女 | 湖北孝感 | | 3 | 黄鱼 | 男 | 湖北罗田 | | 4 | 子栋 | 男 | 湖北洪湖 | | 5 | 子豪 | 女 | 江苏扬州 | | 6 | 小鸟 | 男 | 湖北襄阳 | | 7 | 星爷 | 男 | NULL | | 8 | 戴鹏 | 男 | NULL | | 9 | 秦子琪 | 女 | NULL | +----+-----------+------+--------------+ 9 rows in set (0.00 sec)
右连接:以join右边的表为主
mysql> select student_info.id, student_info.name, student_info.sex, student_addr.addr -> from student_info right join student_addr on student_info.name = student_addr.name; +------+--------+------+--------------+ | id | name | sex | addr | +------+--------+------+--------------+ | 1 | 科比 | 男 | 湖北罗田 | | 6 | 小鸟 | 男 | 湖北襄阳 | | 5 | 子豪 | 女 | 江苏扬州 | | 2 | 毛线 | 女 | 湖北孝感 | | 4 | 子栋 | 男 | 湖北洪湖 | | 3 | 黄鱼 | 男 | 湖北罗田 | +------+--------+------+--------------+ 6 rows in set (0.00 sec) #以join右边的表为主
使用左右连接做三表查询
mysql> select * from (select new.id,new.name,new.sex,new.addr,student_score.MYSQL,student_score.LIUNX,student_score.python from student_score right join (select student_info.id, student_info.name, student_info.sex, student_addr.addr from student_info right join student_addr on student_info.name = student_addr.name) new on student_score.name = new.name) two order by two.id; +------+--------+------+--------------+-------+-------+--------+ | id | name | sex | addr | MYSQL | LIUNX | python | +------+--------+------+--------------+-------+-------+--------+ | 1 | 科比 | 男 | 湖北罗田 | 56 | 87 | 74 | | 2 | 毛线 | 女 | 湖北孝感 | 87 | 95 | 78 | | 3 | 黄鱼 | 男 | 湖北罗田 | 78 | 69 | 90 | | 4 | 子栋 | 男 | 湖北洪湖 | 90 | 95 | 94 | | 5 | 子豪 | 女 | 江苏扬州 | 54 | 67 | 57 | | 6 | 小鸟 | 男 | 湖北襄阳 | 60 | 78 | 87 | +------+--------+------+--------------+-------+-------+--------+ 6 rows in set (0.04 sec)
4.嵌套查询
首先阐述两个名词:
内连接:把查询结果作为where子句的查询条件即为内连接;
子查询:子查询是一个select查询,返回的单个值嵌套在其他查询语句之中,任何可以使用表达式的地方都可以使用子查询。
嵌套查询:在一个查询语句中嵌套有另一个完整的查询语句,就称为嵌套查询,嵌套可以是多层。
mysql> select * from student_addr where name in (select name from student_score where python >= 90); +--------+--------------+ | name | addr | +--------+--------------+ | 子栋 | 湖北洪湖 | | 黄鱼 | 湖北罗田 | +--------+--------------+ 2 rows in set (0.01 sec)