连接查询涉及到主键,外键知识,后面讲
建立两种简单的表作为例子:
mysql> select * from student;
+----+------+-------+
| id | name | s_tid |
+----+------+-------+
| 1 | 小明 | 1 |
| 4 | 小李 | 1 |
| 5 | 小王 | 1 |
| 6 | 小小 | 2 |
+----+------+-------+
4 rows in set (0.02 sec)
mysql> select * from teacher;
+-----+--------+
| tid | tname |
+-----+--------+
| 1 | 王老师 |
| 2 | 小小 |
+-----+--------+
2 rows in set (0.02 sec)
从一张表中单独查询,称为单表查询。
连接查询:跨表查询,把两张或以上的表联合起来查询数据。
连接查询的方式:
所有连接方式都会先生成临时笛卡尔积表,笛卡尔积是关系代数里的一个概念,表示两个表中的每一行数据任意组合。
根据语法的年代分类:
SQL92:1992年的时候出的语法(from 表,表)
SQL99:1999年的时候出现的语法(join on)
根据表连接的方式分类:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接(左连接)
右外连接(右连接)
全连接
直接在from后面把要查询的表用逗号隔开写出来,
条件得用(表名.字段名)来比较,
一般用取别名的方式,这样效率更高。
在from后面起别名,因为它是最开始执行的。
没有起别名。
mysql> select tname,name from teacher,student where teacher.tid=student.s_tid;
+--------+------+
| tname | name |
+--------+------+
| 王老师 | 小明 |
| 王老师 | 小李 |
| 王老师 | 小王 |
| 小小 | 小小 |
+--------+------+
4 rows in set (0.00 sec)
起别名(这样效率更高,减少了表的连接次数)
mysql> select t.tname,s.name from teacher t,student s where t.tid=s.s_tid;
+--------+------+
| tname | name |
+--------+------+
| 王老师 | 小明 |
| 王老师 | 小李 |
| 王老师 | 小王 |
| 小小 | 小小 |
+--------+------+
4 rows in set (0.00 sec)
使用join 来连接表,on来判断条件,
下面是以内连接为例子,inner可以省略。(下面介绍内连接和外连接)
mysql> select t.tname,s.name from teacher t inner join student s on t.tid=s.s_tid;
+--------+------+
| tname | name |
+--------+------+
| 王老师 | 小明 |
| 王老师 | 小李 |
| 王老师 | 小王 |
| 小小 | 小小 |
+--------+------+
4 rows in set (0.00 sec)
inner join..on 字段=字段;
条件是等量关系的,inner可以省略。
mysql> select t.tname,s.name from teacher t inner join student s on t.tid=s.s_tid;
+--------+------+
| tname | name |
+--------+------+
| 王老师 | 小明 |
| 王老师 | 小李 |
| 王老师 | 小王 |
| 小小 | 小小 |
+--------+------+
4 rows in set (0.00 sec)
条件不是等量关系的,inner可以省略。
mysql> select t.tname,s.name from student s join teacher t on s.id between 1 and 5;
+--------+------+
| tname | name |
+--------+------+
| 小小 | 小明 |
| 王老师 | 小明 |
| 小小 | 小李 |
| 王老师 | 小李 |
| 小小 | 小王 |
| 王老师 | 小王 |
+--------+------+
6 rows in set (0.00 sec)
自连接(self join)是SQL语句中经常要用的连接方式,使用自连接可以将自身表的一个镜像当作另一个表来对待,从而能够得到一些特殊的数据。
mysql> select a.name as "大名",b.name as"小名" from student a
join student b where a.id=b.s_tid;
+------+------+
| 大名 | 小名 |
+------+------+
| 小明 | 小明 |
| 小明 | 小李 |
| 小明 | 小王 |
+------+------+
3 rows in set (0.00 sec)
left join on / left outer join on,语法格式
左外连接包含left join左表所有行,如果左表中某行在右表没有匹配,则结果中对应行右表的部分全部为空(NULL).
mysql> select t.tname,s.name from student s left join teacher t on s.s_tid>t.tid;
+--------+------+
| tname | name |
+--------+------+
| NULL | 小明 |
| NULL | 小李 |
| NULL | 小王 |
| 王老师 | 小小 |
+--------+------+
4 rows in set (0.00 sec)
right join on / right outer join on,语法格式
右外连接包含right join右表所有行,如果左表中某行在右表没有匹配,则结果中对应左表的部分全部为空(NULL)。
mysql> select t.tname,s.name from student s right join teacher t on s.s_tid>t.tid;
+--------+------+
| tname | name |
+--------+------+
| 王老师 | 小小 |
| 小小 | NULL |
+--------+------+
2 rows in set (0.01 sec)
完全外连接包含左右两表中所有的行,如果右表中某行在左表中没有匹配,则结果中对应行右表的部分全部为空(NULL),如果左表中某行在右表中没有匹配,则结果中对应行左表的部分全部为空(NULL)。
select 语句中嵌套select语句,被嵌套的select语句被称为子查询。
select
..(select )
from
..(select ) 在from后面,可以把查询结果看出一张新的表
where
..(select )
注意:
对应select后面的子查询来说,这个子查询只能返回一条结果,多于一条报错。
对应select后面的子查询,多于一条报错。:
mysql> select (select id from student) as sname from student;
ERROR 1242 (21000): Subquery returns more than 1 row
mysql> select name,(select id from student where id=1) as sname from student;
+------+-------+
| name | sname |
+------+-------+
| 小明 | 1 |
| 小李 | 1 |
| 小王 | 1 |
| 小小 | 1 |
+------+-------+
4 rows in set (0.00 sec)
在from后面的子查询需要起一个别名,要不然会出现以下错误:
mysql> SELECT id,name from (select * from student where id>1);
ERROR 1248 (42000): Every derived table must have its own alias
mysql> SELECT id,name from (select * from student where id>1)as stu;
+----+------+
| id | name |
+----+------+
| 4 | 小李 |
| 5 | 小王 |
| 6 | 小小 |
+----+------+
3 rows in set (0.00 sec)
同样如果使用运算符连接,子查询的结果只能是一个,不然会报以下错误
mysql> select id,name from student where s_tid=(select tid from teacher);
ERROR 1242 (21000): Subquery returns more than 1 row
mysql> select id,name from student where s_tid=(select tid from teacher where tname=" 小小");
+----+------+
| id | name |
+----+------+
| 6 | 小小 |
+----+------+
1 row in set (0.00 sec)
union的效率更高一些,对于表连接来说,每连接一次新表,则匹配的次数满足笛卡儿积,成倍的翻。
但是union可以减少匹配的次数。在减少匹配的次数的情况下,还能完成两个结果集的拼接
使用union时必须注意,查询的结果必须保证列的数目相同。
如果是oracle还会要求类型也是一样,MySQL不做要求。
mysql> select id,name from student
-> union
-> select tid,tname from teacher;
+----+--------+
| id | name |
+----+--------+
| 1 | 小明 |
| 4 | 小李 |
| 5 | 小王 |
| 6 | 小小 |
| 1 | 王老师 |
| 2 | 小小 |
+----+--------+
6 rows in set (0.00 sec)
limit作用:将查询结果集的一部分取出来。通常使用在分页查询当作。
分页的作用是为了提高用户的体验,因为一次全部都查出来,用户体验差,可以一页一页翻页看。
完整用法:
limit startIndex,length
startIndex是起始下标,length是长度。
起始下标从0开始。
缺省用法:limit 5;这是取前五。
注意:在MySQL当中Limit在order by排序 之后执行。
实例表:
mysql> select * from city;
+----+----------+-----------+-------+
| id | name | parent_id | level |
+----+----------+-----------+-------+
| 1 | 安徽 | 0 | 1 |
| 2 | 江苏 | 0 | 1 |
| 3 | 合肥 | 1 | 2 |
| 4 | 合肥一区 | 3 | 3 |
| 5 | 扬州 | 2 | 2 |
| 6 | 南京 | 2 | 2 |
| 7 | 扬州一区 | 5 | 3 |
| 8 | 扬州二区 | 5 | 3 |
| 9 | 南京一区 | 6 | 3 |
| 10 | 南京二区 | 6 | 3 |
+----+----------+-----------+-------+
10 rows in set (0.00 sec)
mysql> select * from city limit 5;
+----+----------+-----------+-------+
| id | name | parent_id | level |
+----+----------+-----------+-------+
| 1 | 安徽 | 0 | 1 |
| 2 | 江苏 | 0 | 1 |
| 3 | 合肥 | 1 | 2 |
| 4 | 合肥一区 | 3 | 3 |
| 5 | 扬州 | 2 | 2 |
+----+----------+-----------+-------+
5 rows in set (0.00 sec)
limit startIndex,length使用时不需要 加括号
mysql> select * from city limit 0,5;
+----+----------+-----------+-------+
| id | name | parent_id | level |
+----+----------+-----------+-------+
| 1 | 安徽 | 0 | 1 |
| 2 | 江苏 | 0 | 1 |
| 3 | 合肥 | 1 | 2 |
| 4 | 合肥一区 | 3 | 3 |
| 5 | 扬州 | 2 | 2 |
+----+----------+-----------+-------+
5 rows in set (0.00 sec)
select
...
from
...
group by
...
having
...
order by
...
limit
...
执行顺序:1,from 2.where 3,group by 4,having
5,select 6,order by 7,limit...