TODO
不连接交叉连接(即用,
在from
中分隔两表)和内连接的区别,是不是都可以产生笛卡尔积?- 连接时用的
on
和判断时用的where
如何正确使用,同时使用时如何正确使用?详见183方法一 - 使用
group by
时,只要是select
中非聚集函数的列,都要在group by
当中
NOTE
1. 交叉连接与隐式内连接的区别
个人理解是,没有where
就是交叉连接,有where
就是隐式内连接。产生的中间表均为笛卡尔积,区别在于隐式内连接会对产生的笛卡尔积通过where进行过滤得到结果。
1 | SELECT * FROM 表1 CROSS JOIN 表2; --交叉连接 |
隐式内连接不用on
语句,而用where
1 | SELECT * FROM 表1,表2 where 表1.关系字段 = 表2.关系字段 --隐式内连接 |
2. on
, where
, having
的正确使用
on
用于建立关联关系,where
用于筛选关联关系。on
是用于生成临时表时使用的条件。在外连接中,不管on
的条件是否为真,都会返回left join
中的左表信息,或者right join
中的右表信息。where
是在临时表生成之后对该临时表过滤用的条件,过滤掉条件不为真的所有信息。在内连接中,条件放在
on
和where
没区别,返回的结果集是相同的。在优先级方面,on > where > 聚合函数 > having:
表关联生成临时表, on 条件生效(此时的临时表会因为left join或right join的特性而一定带有主表的记录,也就是主表的记录不会被 on 条件过滤掉) –> 临时表生成完毕,where条件过滤临时表(where条件过滤时因为临时表已经生成完毕,因此不会再具有left join或right join的特性,也就是主表记录也会被where条件过滤掉) –> 临时表过滤完毕,聚合函数进行运算 –> 聚合函数运算完毕,having生效对运算完毕的临时表进行过滤 –>最终的结果表
原文链接:https://blog.csdn.net/qq_27607579/article/details/83787592
having
只与group by
连用, 即在分组过后过滤数据,条件中通常包含聚合函数。①
WHERE
子句用来筛选FROM
子句中指定的操作所产生的行。
②GROUP BY
子句用来分组WHERE
子句的输出。
③HAVING
子句用来从分组的结果中筛选行。
181. Employees Earning More Than Their Managers
来源:https://leetcode.com/problems/employees-earning-more-than-their-managers/description/
考察:同一个表内的信息对比,需要把一张表看作两张表分别对比条件进行查询,也就是从这个表里获取两次信息。可以用到内连接,也可以不用内连接直接查询。
Description
Employee 表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,此外还有一列对应员工的经理的 Id。
1 | +----+-------+--------+-----------+ |
给定 Employee 表,编写一个 SQL 查询,该查询可以获取收入超过他们经理的员工的姓名。在上面的表格中,Joe 是唯一一个收入超过他的经理的员工。
1 | +----------+ |
Solution
此处还要注意题目还要求最终输出结果的表头为Employee
方法一:
1 | select e1.Name as Employee --更改字段名,as可缺省 |
在where
语句之前,可以理解为交叉连接产生笛卡尔积,查询结果有4×4=16个。一般情况下不会使用交叉连接,这这业务需求比较少见。
在有where
语句时,语句表示一个隐性内连接,产生的中间表仍为笛卡尔积,结果用where
语句过滤掉
方法二:内连接
1 | select e1.Name as Employee |
方法三:子查询
1 | select e1.Name as Employee |
183. Customers Who Never Order
来源:https://leetcode.com/problems/customers-who-never-order/description/
考察:查找不存在的数据,连接用is null
,子查询用not in
Description
某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。
Customers 表:
1 | +----+-------+ |
Orders 表:
1 | +----+------------+ |
例如给定上述表格,你的查询应返回:
1 | +-----------+ |
Solution
方法一:左外连接
要查询Orders
表中不存在,但在Customers
表中存在的CustomerId
,把Orders
放在左连接的右边,就可以查询出Orders
中CustomerId
为null
的数据
1 | select c.Name as Customers |
方法二:子查询
查询不存在的值,可以用where
与not in
结合的方法,利用子查询
1 | select Name as Customers |
184. Department Highest Salary
来源:https://leetcode.com/problems/department-highest-salary/description/
考察:使用join
和in
。in
可以用于多个字段,子查询或临时表
Description
Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id。
1 | +----+-------+--------+--------------+ |
Department 表包含公司所有部门的信息。
1 | +----+----------+ |
编写一个 SQL 查询,找出每个部门工资最高的员工。例如,根据上述给定的表格,Max 在 IT 部门有最高工资,Henry 在 Sales 部门有最高工资。
1 | +------------+----------+--------+ |
Solution
首先可以在Employee
表中根据DepartmentId
分组找到每组最高Salary
所代表的信息,也就是先创建一个临时表,包含了部门员工的最大薪资:
此处特别注意: select
中非聚集函数的列,都要在 group by
中
1 | select DepartmentId, max(Salary) |
得出结果为
1 | | DepartmentId | MAX(Salary) | |
然后,把表 Employee
和 Department
连接,再在这张临时表里用 IN
语句查询部门名字和工资的关系。在in
语句中可以同时使用多个字段
1 | select d.Name Department, e.Name Employee, Salary |