多表查询有两种方式:1)连接查询;2)合并查询。这里先讲连接查询
一、概念:
在关系数据库中,一个实例数据库可能包含多张关系表,这些关系表可能存在某种联系,我们可以根据这些联系,将表与表连接起来。这种查询设计称为连接查询。在了解连接查询之前,我们先科普一些基础知识。 1、笛卡尔积:那什么是笛卡尔积呢?域或关系在连接时的所有可能的元组集合。 基本定义:两个关系R,S ,其度分别为n,m,则它们的笛卡尔积是所有这样的元组集合:
其中,元组的前n个分量是R中的一个元组,后m个分量是S 中的一个元组。举一个例子:
2、θ连接:更进一步,我们再来讲一个笛卡尔积的“变种”,即θ连接。它是从两个关系的笛卡尔积中选取给定属性间满足一定条件的元组集合:
其中θ 为算术比较符,θ∈{ > ,≥ ,< ,≤ ,= ,≠} ,举一个例子:
连接查询的基本概念:
在关系数据库中,一个实例数据库可能包含多张关系表,这些关系表可能存在某种联系,我们可以根据这些联系,将表与表连接起来。这种查询设计称为连接查询。连接查询本质上由广义笛卡尔积演变而来的。 基本定义:通过连接运算符进行多表的查询 图示描述:
二、连接方式:
连接查询通过广义笛卡尔积的形式将多张表的数据连接在一起,从而生成一张描述结果集的表,常见的有三种连接方式:
1、内连接:
我们先来学习内连接的相关知识。内连接实际上就是θ连接的SQL实现,是通过比较运算符(join或inner join)查询两张表的关联数据,只返回符合条件的行。一般情况下,两张表的连接条件都是依照外码约束来建立的。例:
现在要查询软件开发部中的所有员工,输出员工的部门名称D、员工姓名E和员工年龄A等信息。这里的答案有两种写法:
1)一种是标准的内连接的写法(from 表1 inner join 表2 on 条件):
2)另一种是比较老旧的写法(from 表1,表2 where 条件):
2、交叉连接:
交叉连接使用cross join关键字,它的用法有两种: 1)执行 select * from A cross join B 的结果集,实际上就是关系A和关系B的笛卡尔积。 2)执行 select * from A cross join B where A.xx=B.xx ...; 的结果集,实际上就是关系A和关系B的θ连接(内连接)。 例一:
如果每个员工都没有分配部门,即dept_id列的值均为null,那么每一位员工都有哪些分配方案呢?针对这种情况,我们就可以使用不带where字句的交叉连接,它会将连接的所有可能都列举出来,sql语句可以这么写:select * from employee cross join dept;查询得到的结果集如下:
有点像两张表相乘得到的结果。
例二:
现在想要查询软件开发部有哪些员工,可以这样写:
和内连接的效果一样。
3、外连接:
(1.)左外连接: 左外连接使用 left join 或 left outer join 关键字,执行结果中包含左表所有行,如果左表中某行在右表没有匹配,则结果中对应行右表的部分全部为空(NULL)。
例:
现在要获取所有员工信息,输出部门D、员工姓名E,要求显示所有部门,无论该部门是否有员工,如果没有显示null。可以这样写:
查询得到的结果集如下:
(2.)右外连接: 右外连接使用 right join 或 right outer join 关键字,执行结果中包含右表所有行,如果右表中某行在左表没有匹配,则结果中对应行左表的部分全部为空(NULL)。它实际上和左外连接是“左手和右手”的问题。
现在要获取所有员工信息,输出部门D、员工姓名E,要求显示所有员工,无论该员工是否有部门归属,如果没有显示null。可以这样写:
得到的结果集如下:
(3.)全外连接: 全外连接使用 full join 或 full outer join 关键字,执行结果中包含左表和右表所有行,如果右表中某行在左表没有匹配,则结果中对应行左表的部分全部为空(NULL),反之亦然。
现在想要获取所有员工信息,输出部门名称D、员工姓名E,要求显示所有部门、员工,没有显示null。
得到的结果集如下:
三、连接查询注意事项:
1、多表连接查询去重复问题:可以加个group by id;如:
<!--获取分页数据--> select * from user u left join userrole ur on u.id=ur.uid left join role r on r.rid=ur.rid where 1=1 group by u.id limit 0,7 </select>2、多表连接查询求count总数:
select count(*) from (select u.id from user u left join userrole ur on u.id=ur.uid left join role r on r.rid=ur.rid group by u.id) as a同理,这里group by u.id是去重复的,而as a是为这个内表查询取别名,虽然没有用处,但是去掉会报错。
3、连接查询时,需要做计算,可以把计算结果作为一张表,示例:
SELECT ci.province, ci.city, ci.district, cpi.account, cpi. NAME, COALESCE (sp.serviceNum, 0) AS serviceSchoolNumber FROM t_user cpi LEFT JOIN t_user_role ci ON cpi.user_id = ci.user_id LEFT JOIN ( SELECT COUNT(*) AS serviceNum, account FROM user_school GROUP BY account ) AS sp ON sp.account = cpi.account WHERE cpi.account = 'zhangsan' and ci.role_code = 'xtgly'