【mysql 连接查询 04】

#进阶6:连接查询

含义:又称多表查询,当查询的字段来自多个表时,就会用到连接查询

分类:

按年份分类:

sql92:等值,非等值,自连接

sql99:内连接,外连接,交叉连接

按功能分类:

内连接:等值连接、非等值连接、自连接

外连接:左外连接、右外连接、全外连接

交叉连接

#sql92:1、等值链接:

 【mysql 连接查询 04】

|-- 多表等值连接的结果为多表的交集部分;

|-- n表连接,至少需要n-1个链接条件;

|-- 多表的顺序没有要求

|-- 一般需要为表起别名

|-- 可以搭配前面结束的所有子句使用,比如:排序,分组,
#案例:查询员工名和对应的部门名

SELECT last_name,department_name FROM employees,departments WHERE employees.`department_id`=departments.`department_id`;

#为表起别名   注意:如果为表起了别名,则查询的字段就不能使用原来的表名去限定
#查询员工名,工种号,工种名

SELECT last_name,e.job_id,job_title FROM employees e,jobs j WHERE e.`job_id`=j.`job_id`;

#可以加筛选?案例1:查询有奖金的员工名、部门名

SELECT
  last_name,
  department_name,
  commission_pct
FROM
  departments d,
  employees e
WHERE d.`department_id` = e.`department_id`
  AND e.`commission_pct` IS NOT NULL ;

#案例2:查询城市名中第二个字符为o的部门名和城市名

SELECT department_id,city FROM departments d,locations l WHERE d.`location_id`=l.`location_id` AND l.`city` LIKE '_o%';

#可以加分组?
#案例1:查询每个城市的部门个数

SELECT COUNT(*) 个数,city FROM locations l,departments d WHERE l.`location_id`=d.`location_id` GROUP BY city;

#案例2:查询出有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资

SELECT
  department_name,
  d.`manager_id`,
  MIN(salary)
FROM
  `departments` d,
  `employees` e
WHERE d.`department_id` =e.`department_id` AND e.commission_pct IS NOT NULL
GROUP BY department_name;

#可以加排序?
#案例:查询每个工种的工种名和员工的个数,按员工个数降序

SELECT
  job_title,
  COUNT(*) 个数
FROM
  employees e,
  jobs j
WHERE e.`job_id` = j.`job_id`
GROUP BY job_title
ORDER BY 个数 DESC ;

#可以实现三表链接?
#案例:查询员工名,部门名和所在的城市

SELECT
  last_name,
  department_name,
  city
FROM
  employees e,
  departments d,
  locations l
WHERE
  e.`department_id`=d.`department_id` AND d.`location_id`=l.`location_id`;

#2、非等值链接:

 【mysql 连接查询 04】

#案例1:查询员工的工资和工资级别

SELECT salary,grade_level FROM employees e,job_grades g WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal`;

#3、自链接:把原本的表当做另外的一张或更多张表

#案例:查询员工名和上级的名称  (把employee_id和manager_id相同的名称作为员工和上级)

SELECT e.last_name,e.employee_id,m.last_name,m.employee_id FROM employees e,employees m WHERE e.`employee_id`=m.`manager_id`;

 sql99
语法:

SELECT 查询列表
FROM 表1 别名【连接类型】JOIN 表2 别名 ON 连接条件

【WHERE 筛选条件】

【GROUP BY 分组】

【HAVING 筛选条件】

【ORDER BY 排序条件】

分类:
内连接:INNER
外连接: 左外:LEFT【OUTER】 右外:RIGHT【OUTER】全外:FULL【OUTER】
交叉连接;CROSS
# 1、内连接
语法:

SELECT 查询列表  FROM 表1 别名 INNER JOIN 表2 别名 ON 连接条件;

分类:等值,非等值,自连接
#等值链接
#案例1:查询员工名,部门名

SELECT last_name,department_name FROM employees e INNER JOIN departments d ON e.`department_id`=d.`department_id`;

#案例2:查询名字中包含e的员工名和工种名

SELECT last_name,job_title FROM employees e INNER JOIN jobs j ON e.`job_id`=j.`job_id` WHERE e.`last_name` LIKE '%e%';

#案例3:查询部门个数>3的城市名和部门个数

1)先查询每个城市的部门个数
2)在1结果上筛选部门个数>3
SELECT
  COUNT(*) 部门个数,
  city
FROM
  departments d
  INNER JOIN locations l
    ON d.`location_id` = l.`location_id`
GROUP BY city
HAVING COUNT(*)>3;

#案例4:查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序

SELECT
  department_name,
  COUNT(*) 员工个数
FROM
  departments d
  INNER JOIN employees e
    ON d.`department_id` = e.`department_id`
GROUP BY department_name
HAVING 员工个数 > 3
ORDER BY 员工个数 DESC ;

#案例5:查询员工名、部门名,工种名,并按部门名降序

SELECT
  last_name,
  department_name,
  job_title
FROM
  employees e
  INNER JOIN departments d
  ON e.`department_id` = d.`department_id`
  INNER JOIN jobs j
  ON  e.`job_id`=j.`job_id`
 ORDER BY department_name DESC;

#非等值链接
#查询员工的工资级别

SELECT salary,grade_level FROM employees e JOIN job_grades j ON e.`salary` BETWEEN j.`lowest_sal` AND j.`highest_sal`;

#自链接
#查询员工的名字,上级的名字

SELECT e.last_name,m.last_name FROM employees e JOIN employees m ON e.`employee_id`=m.`manager_id`

#外链接:
应用场景:一个表中有,另外一个表中没有
特点:
1、外链接查询结果为主表中的所有记录
   如果从表中有和它匹配的,则显示匹配的值
   如果从表中没有和它匹配的,则显示NULL
   外链接查询结果=内链接结果+主表中有而从表没有的记录
2、左外链接,LEFT JOIN左边的数主表
   右外连接,RIGHT JOIN右边的是主表
3、左外和右外交换两个表的顺序,可以实现同样的效果
#左外链接:案例:查询男朋友 不在男神表的女神名

SELECT b.name,bo.* FROM beauty b LEFT JOIN boys bo ON bo.id = b.`boyfriend_id` WHERE bo.id IS NULL  ;

#右外连接

SELECT b.name,bo.* FROM boys bo RIGHT JOIN beauty b  ON bo.id = b.`boyfriend_id` WHERE bo.id IS NULL  ;

#案例1;查询哪个部门没有员工
#左外 (查询的是部门的信息,所以主表是部门表)

SELECT
  employee_id,
  d.department_id
FROM
  departments d
  LEFT OUTER JOIN employees e  
    ON e.department_id = d.department_id
WHERE e.`employee_id` IS NULL;

#交叉链接

SELECT b.*,bo.* FROM beauty b CROSS JOIN boys bo;

#案例1:查询编号>3的女神的男朋友信息,如果有则列出详细,如果没有,用null填充

SELECT bo.id 女id,bo.`name`,b.id 男id,b.`boyName` FROM beauty bo LEFT JOIN boys b ON bo.`boyfriend_id`=b.`id` WHERE bo.id>3;

#案例2:查询哪个城市没有部门

SELECT
  city,
  d.`department_id`
FROM
  departments d
  RIGHT OUTER JOIN locations l
    ON d.`location_id` = l.`location_id`
WHERE department_name IS NULL
GROUP BY city;

#案例3:查询部门名为SAL或IT的员工信息

SELECT
  e.*,
  department_name
FROM
  departments d
  LEFT JOIN employees e
    ON d.`department_id` = e.`department_id`
WHERE d.`department_name` IN ('SAL','IT');

#简单使用

SELECT SUM(salary) FROM employees;
SELECT AVG(salary) FROM employees;
SELECT MAX(salary) FROM employees;
SELECT MIN(salary) FROM employees;
SELECT COUNT(salary) FROM employees;

SELECT SUM(salary) 和,AVG(salary) 平均值,MAX(salary) 最大值, MIN(salary) 最小值,COUNT(salary) 个数 FROM employees;

#特点

  • 1、SUM AVG 一般用于处理数值型
  • 2、MAX,MIN,COUNT可以处理任何类型
  • 3、以上函数都忽略NULL值
  • 4、可以和DISTINCT搭配使用
  • 5、一般使用COUNT(*)用作统计行数
  • 6、和分组函数一同查询的字段要求是GROUP BY后的字段

#和DISTINCT搭配使用

SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;
SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;

#count函数的详细介绍

SELECT COUNT(salary) FROM employees;
SELECT COUNT(*) FROM employees; # 常用,原理如果有多列的时候,只要多列内对应的每一行有一个部位null都能计数
SELECT COUNT(1) FROM employees; # 原理:在列的最左侧添加一列,并且列内的每一行都为1,select count(5)表明列内的每一行都为5

#查询员工表中的最大入职时间和最小入职时间的相差天数(DIFFRENCE)

SELECT DATEDIFF(MAX(hiredate),MIN(hiredate)) DIFFRENCE FROM employees;

#分组查询
语法:

   select 分组函数,列(要求出现在group by的后面)
   from 表
   【where 筛选条件】
   group by 分组列表
   【order by 子句】

注意:查询列表必须特殊,要求是分组函数和group by后出现的字段
特点:
 分组查询中的筛选条件分为两种
        数据源        位置            关键字
 分组前筛选    原始表        group by子句的前面    where
 分组后的筛选    分组后的结果集    group by子句的后面    having

 1) 分组函数做条件肯定是放在having子句中
 2)能用分组前筛选的,就有限考虑使用分组前筛选

#案例1:查询每个工种的最高工资

SELECT MAX(salary) 最高工资,job_id 工种 FROM employees GROUP BY job_id;

#案例2:查询每个位置上的部门个数

SELECT  COUNT(*) ,location_id FROM departments GROUP BY location_id;

#添加筛选条件
#案例1、查询邮箱中包含a字符,每个部门的平均工资

SELECT AVG(salary),department_id FROM employees WHERE email LIKE '%a%' GROUP BY department_id;

#案例2、查询有奖金的每个领导手下员工的最高工资

SELECT MAX(salary),`manager_id` FROM `employees` WHERE commission_pct IS NOT NULL GROUP BY `manager_id`;

#添加复杂的筛选条件
#案例1:查询那个部门的员工个数>2

分步1:查询每个部门的员工个数
SELECT COUNT(*) 个数 ,department_id FROM employees GROUP BY department_id;

分步2:根据1的结果进行筛选,查询那个部门的员工个数大于2
SELECT COUNT(*) 个数 ,department_id FROM employees GROUP BY department_id  HAVING COUNT(*)>2 ;  #HAVING关键字

#案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资

分步1:每个工种有奖金的员工的最高工资。分步2:根据1的结果筛选,最高工资>12000
SELECT MAX(salary),job_id FROM employees WHERE commission_pct IS NOT NULL GROUP BY job_id HAVING  MAX(salary)>12000;

#案例3:查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个,以及其最低工资

查询领导编号>102的每个手下的最低工资和领导编号
SELECT MIN(salary),manager_id FROM employees WHERE manager_id>102 GROUP BY manager_id HAVING MIN(salary)>5000;