为了便于说明下文中的例子,首先创建如下三张表:
mysql> SELECT * FROM student;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 1 | 张三 | 18 | 男 |
| 2 | 李四 | 20 | 女 |
+----+------+-----+-----+
2 rows in set (0.00 sec)
mysql> SELECT * FROM subject;
+------+---------+---------+------------------+
| id | subject | teacher | description |
+------+---------+---------+------------------+
| 1001 | 语文 | 王老师 | 本次考试比较简单 |
| 1002 | 数学 | 刘老师 | 本次考试比较难单 |
+------+---------+---------+------------------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM score;
+----+------------+------------+-------+
| id | student_id | subject_id | score |
+----+------------+------------+-------+
| 1 | 1 | 1001 | 80 |
| 2 | 2 | 1001 | 60 |
| 3 | 1 | 1002 | 70 |
| 4 | 2 | 1002 | 60.5 |
+----+------------+------------+-------+
子查询
子查询可以把一个查询嵌套在另一个查询当中的查询。
SELECT colunm FROM table1 WHERE condition
子查询一般分为内部查询和外部查询,内部查询即为condition
语句,外部查询即上例中的SELECT colunm FROM table1 WHERE..
如查询score
表中的语文成绩:
mysql> SELECT score FROM score WHERE subject_id = (
-> SELECT id FROM subject WHERE subject='语文'
-> );
+-------+
| score |
+-------+
| 80 |
| 60 |
+-------+
该例中SELECT score FROM score WHERE subject_id =..
为外部查询,SELECT id FROM subject WHERE subject='语文'
为内部查询。
子查询的结果均为外部查询的表,而不能包括内部查询的结果。对于上例,也就说是,我们查询到的结果,均为score
中的内容,而不能获得subject
表中的内容。
联结查询
子查询只能显示一张表的数据,但我们想要同时查询显示多张表的数据时,就可以使用联结查询。
内联结
又叫等值联结,基于两个表之间的相等测试。查询两个或多个表的交集。
语法:
SELECT * FROM table1 AS t1 INNER JOIN table2 AS t2 ON t1.column = t2.column;
- 例子
同时显示学生姓名,科目和成绩
mysql> SELECT name , subject , score
-> FROM score AS s
-> INNER JOIN student AS stu ON s.student_id = stu.id
-> INNER JOIN subject AS sub ON s.subject_id = sub.id;
+------+---------+-------+
| name | subject | score |
+------+---------+-------+
| 张三 | 语文 | 80 |
| 李四 | 语文 | 60 |
| 张三 | 数学 | 70 |
| 李四 | 数学 | 60.5 |
+------+---------+-------+
description
列只存在于subject
表中,不是三张表的交集。因此,当我们内联结三张表后是查询不到description
的。
mysql> SELECT desctiption
-> FROM score AS s
-> INNER JOIN student AS stu ON s.student_id = stu.id
-> INNER JOIN subject AS sub ON s.subject_id = sub.id;
ERROR 1054 (42S22): Unknown column 'desctiption' in 'field list'
外联结
以某张表为主,取出里面的所有记录, 然后每条与另外一张表进行连接: 不管能不能匹配上条件,最终都会保留: 能匹配,正确保留; 不能匹配,其他表的字段都置空NULL.
外联结分为左外联结和右外联结。左外联结即以左边的表为主表;右外联结即以右边的表为主表。所谓左右,即为代码中表的顺序,第一个为左,最后一个为右。
- 例子
为了使外联结的示例更明显,删除student
表中id=1
的记录
mysql> DELETE FROM student WHERE id = 1;
Query OK, 1 row affected (0.20 sec)
mysql> SELECT * FROM student;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 2 | 李四 | 20 | 女 |
+----+------+-----+-----+
以score
为主表,左外联结subject
和student
mysql> SELECT * FROM score AS s
-> LEFT JOIN subject AS sub ON s.subject_id = sub.id
-> LEFT JOIN student AS stu ON s.student_id = stu.id;
+----+------------+------------+-------+------+---------+---------+------------------+------+------+------+------+
| id | student_id | subject_id | score | id | subject | teacher | description | id | name | age | sex |
+----+------------+------------+-------+------+---------+---------+------------------+------+------+------+------+
| 2 | 2 | 1001 | 60 | 1001 | 语文 | 王老师 | 本次考试比较简单 | 2 | 李四 | 20 | 女 |
| 4 | 2 | 1002 | 60.5 | 1002 | 数学 | 刘老师 | 本次考试比较难单 | 2 | 李四 | 20 | 女 |
| 1 | 1 | 1001 | 80 | 1001 | 语文 | 王老师 | 本次考试比较简单 | NULL | NULL | NULL | NULL |
| 3 | 1 | 1002 | 70 | 1002 | 数学 | 刘老师 | 本次考试比较难单 | NULL | NULL | NULL | NULL |
+----+------------+------------+-------+------+---------+---------+------------------+------+------+------+------+
注意到三四行的学生相关信息为NULL
,因为该两行的student_id
为1,student
表中不存在该学生,因此查不到。
而如果以student
表为主表,则查询的结果只有两条记录。这是因为student
中只有id
为2的学生,三张表中与该生有关的记录只有两条。
如下例,以student
为主表,右外联结score
和subject
mysql> SELECT * FROM score AS s
-> RIGHT JOIN subject AS sub ON s.subject_id = sub.id
-> RIGHT JOIN student AS stu ON s.student_id = stu.id;
+------+------------+------------+-------+------+---------+---------+------------------+----+------+-----+-----+
| id | student_id | subject_id | score | id | subject | teacher | description | id | name | age | sex |
+------+------------+------------+-------+------+---------+---------+------------------+----+------+-----+-----+
| 2 | 2 | 1001 | 60 | 1001 | 语文 | 王老师 | 本次考试比较简单 | 2 | 李四 | 20 | 女 |
| 4 | 2 | 1002 | 60.5 | 1002 | 数学 | 刘老师 | 本次考试比较难单 | 2 | 李四 | 20 | 女 |
+------+------------+------------+-------+------+---------+---------+------------------+----+------+-----+-----+
因此,外联结就是在主表的记录基础上,查询联结的表的并集。
组合查询
组合多个查询语句
- 对单个表执行多个查询,按照单个查询返回数据。
查询score
表中分数大于70并且学生id 为1的记录:
mysql> SELECT * FROM score WHERE score > 70
-> UNION
-> SELECT * FROM score WHERE student_id = 1;
+----+------------+------------+-------+
| id | student_id | subject_id | score |
+----+------------+------------+-------+
| 1 | 1 | 1001 | 80 |
| 3 | 1 | 1002 | 70 |
+----+------------+------------+-------+
当然也可以使用AND
写为一句:
mysql> SELECT * FROM score WHERE score > 70 AND student_id = 1;
+----+------------+------------+-------+
| id | student_id | subject_id | score |
+----+------------+------------+-------+
| 1 | 1 | 1001 | 80 |
+----+------------+------------+-------+
- 在单个查询中,从不同表中返回类似结构的数据。
比如,复制student
表的结构创建表student_2
,并添加一条记录:
mysql> CREATE TABLE student_2 LIKE student;
Query OK, 0 rows affected (0.96 sec)
mysql> INSERT INTO student_2 VALUES (3,'王五',17,'男');
Query OK, 1 row affected (0.10 sec)
组合查询
mysql> SELECT * FROM student
-> UNION
-> SELECT * FROM student_2;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 2 | 李四 | 20 | 女 |
| 3 | 王五 | 17 | 男 |
+----+------+-----+-----+