当我们查询的数据来源于多张表的时候,我们需要用到连接查询,连接查询使用率非常高,是务必掌握的。联结( JOIN )就是将其他表中的列添加过来,进行“添加列”的集合运算。联结大体上分为内联结和外联结两种。
笛卡尔积( 交叉联结:CROSS JOIN)简单点理解:有两个集合A和B,笛卡尔积表示A集合中的元素和B集合中的元素任意相互关联产生的所有可能的结果。
假如A中有m个元素,B中有n个元素,A、B笛卡尔积产生的结果有m*n个结果,相当于循环遍历两个集合中的元素,任意组合。
java伪代码表示如下:
for(Object eleA : A){
for(Object eleB : B){
System.out.print(eleA+","+eleB);
}
}
过程:拿A集合中的第1行,去匹配集合B中所有的行,然后再拿集合A中的第2行,去匹配集合B中所有的行,最后结果数量为m*n。
笛卡尔积语法:
select 字段 from 表1,表2[,表N];
或者
select 字段 from 表1 join 表2 [join 表N];
内联结也称为INNER JOIN,相当于在笛卡尔积的基础上添加了内联结的条件,当没有联结条件是便上升为笛卡尔积。
java伪代码表示如下:
for(Object eleA : A){
for(Object eleB : B){
if (联结条件是否为true)
System.out.print(eleA+","+eleB);
}
}
INNER JOIN语法:
select 字段 from 表1 join 表2 ON 联结条件;
或者
select 字段 from 表1 inner join 表2 ON 联结条件;
或者
select 字段 from 表1,表2 [where 关联条件];
内联接建议使用第三种表示方法,更加简洁。
内联结查询如下:
mysql> SELECT
t1.emp_name,
t2.team_name
FROM
t_employee t1
INNER JOIN
t_team t2
ON
t1.team_id = t2.id;
+---------------+-----------+
| emp_name | team_name |
+---------------+-----------+
| Lw中 | 程序员组 |
| 张三 | 测试组 |
| 李四 | java组 |
+---------------+-----------+
3 rows in set (0.00 sec)
示例1:有联结条件
select
t1.emp_name,t2.team_name
from
t_employee as t1 inner join t_team as t2
on
t1.team_id = t2.id;
示例2:无联结条件
select
t1.emp_name,t2.team_name
from t_employee as t1 inner join t_team as t2;
示例3:组合条件查询
select
t1.emp_name,t2.team_name
from
t_employee as t1, t_team as t2
where
t1.team_id = t2.id and t2.team_name = '底层程序员组';
内联结也称为OUTER JOIN,外连接涉及到2个表,分为:主表和从表,要查询的信息主要来自于哪个表,谁就是主表。
外联结查询结果会输出主表中所有记录。如果从表中有和它匹配的,则显示匹配的值,这部分相当于内联结;如果从表中没有和它匹配的,则显示null。
最终:外联结查询结果 = 内联结的结果 + 主表中有的而内联结结果中没有的记录。
外联结分为2种:
左外联结:使用left join关键字,left join左边的是主表。
右外联结:使用right join关键字,right join右边的是主表。
左外联结:使用left join关键字,left join左边的是主表。
LEFT JOIN语法:
select 列 from 主表 left join 从表 on 连接条件;
示例:
mysql> SELECT
t1.emp_name,
t2.team_name
FROM
t_employee t1
LEFT JOIN
t_team t2
ON
t1.team_id = t2.id;
+---------------+-----------+
| emp_name | team_name |
+---------------+-----------+
| Lw中 | 程序员组 |
| 张三 | 测试组 |
| 李四 | java组 |
| 王五 | NULL |
| 赵六 | NULL |
+---------------+-----------+
5 rows in set (0.00 sec)
右外联结:使用right join关键字,right join右边的是主表。
RIGHT JOIN语法:
select 列 from 从表 right join 主表 on 连接条件;
示例:
mysql> SELECT
t2.team_name,
t1.emp_name
FROM
t_team t2
RIGHT JOIN
t_employee t1
ON
t1.team_id = t2.id;
+-----------+---------------+
| team_name | emp_name |
+-----------+---------------+
| 程序员组 | Lw中 |
| 测试组 | 张三 |
| java组 | 李四 |
| NULL | 王五 |
| NULL | 赵六 |
+-----------+---------------+
5 rows in set (0.00 sec)
全联结:使用full join关键字,把左右两张表的数据都查询出来,不管匹配与否。mysql是不支持full join的,但仍然可以同过左外连接+ union+右外连接实现
union全联结查询语法如下:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
通常联结只涉及 2 张表,但有时也会出现必须同时联结 3 张以上的表
的情况,原则上联结表的数量并没有限制。
三表以上联结语法:
select 列 from 表1 inner join 表2 on 连接条件 inner join 表3 on 联结条件 inner join ...;
假设现在有三张表,departments、dept_emp、employees,需要查找所有员工的last_name和first_name以及对应的dept_name
departments表
CREATE TABLE `departments` (
`dept_no` char(4) NOT NULL,
`dept_name` varchar(40) NOT NULL,
PRIMARY KEY (`dept_no`));
dept_emp表
CREATE TABLE `dept_emp`
(`emp_no` int(11) NOT NULL comment '所有的员工编号',
`dept_no` char(4) NOT NULL comment '部门编号',
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
employees表
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
查询语句如下:
select
e.last_name, e.first_name, d.dept_name
from
employees e
inner join
dept_emp de on e.emp_no = de.emp_no
inner join
departments d on de.dept_no = d.dept_no;