ToB企服应用市场:ToB评测及商务社交产业平台

标题: 6. 多表查询 [打印本页]

作者: 温锦文欧普厨电及净水器总代理    时间: 2022-8-9 21:57
标题: 6. 多表查询
6.1 一个案例引入多表查询

现在有两张表employees和department。

现在的要求是
  1. # 查询每个员工的姓名和对应的部门名称
  2. SELECT last_name, department_name
  3. FROM employees, departments;
  4. # 部分结果举例
  5. /*
  6. | Gietz       | Payroll              |
  7. | Gietz       | Recruiting           |
  8. | Gietz       | Retail Sales         |
  9. | Gietz       | Government Sales     |
  10. | Gietz       | IT Helpdesk          |
  11. | Gietz       | NOC                  |
  12. | Gietz       | IT Support           |
  13. | Gietz       | Operations           |
  14. | Gietz       | Contracting          |
  15. | Gietz       | Construction         |
  16. | Gietz       | Manufacturing        |
  17. | Gietz       | Benefits             |
  18. | Gietz       | Shareholder Services |
  19. | Gietz       | Control And Credit   |
  20. | Gietz       | Corporate Tax        |
  21. | Gietz       | Treasury             |
  22. | Gietz       | Accounting           |
  23. | Gietz       | Finance              |
  24. | Gietz       | Executive            |
  25. | Gietz       | Sales                |
  26. | Gietz       | Public Relations     |
  27. | Gietz       | IT                   |
  28. | Gietz       | Shipping             |
  29. | Gietz       | Human Resources      |
  30. | Gietz       | Purchasing           |
  31. | Gietz       | Marketing            |
  32. | Gietz       | Administration       |
  33. +-------------+----------------------+
  34. 2889 rows in set (1.04 sec)
  35. */
复制代码
从结果上看最终查询的数量是 employees表的行数 * departments表的行数 (107 * 27 )。
那么为什么会出现这种现象呢?
笛卡尔积

这里需要引入笛卡尔积的概念,什么是笛卡尔积呢?

从图中可以看出,笛卡尔积就是所有可能性结果,也称之为交叉连接,英文是CROSS JOIN,SQL99中也是使用CROSS JOIN来表示交叉连接,作用就是可以将任意表进行连接,哪怕两张表不相关。
笛卡尔积错误的产生
为了避免笛卡尔积的条件,需要用WHERE加入有效的连接条件
  1. # 查询每个员工的姓名和对应的部门名称
  2. SELECT last_name, department_name
  3. FROM employees, departments
  4. WHERE employees.department_id = departments.department_id;
复制代码
6.2 多表查询的分类

等值连接 VS 非等值连接

等值连接

利用一张表的某列的值和另外一张表中某列的值相等的关系,把多余的数据过滤掉
刚才的查询就是一个典型的等值连接
  1. # 查询每个员工的姓名和对应的部门名称
  2. SELECT last_name, department_name
  3. FROM employees, departments
  4. WHERE employees.department_id = departments.department_id;
复制代码
非等值连接

除了利用相等,还可以利用范围条件实现两个表的查询。
  1. # 查询所有员工的工资等级
  2. SELECT e.last_name, e.salary, j.grade_level
  3. FROM employees e, job_grades j
  4. WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal;
复制代码
自连接 VS 非自连接


  1. # 查询employees表,返回“Xxx works for Xxx”
  2. SELECT CONCAT(worker.last_name," works for ",manager.last_name)
  3. FROM employees worker, employees manager
  4. WHERE worker.manager_id = manager.employee_id;
  5. # 查询出last_name为 ‘Chen’ 的员工的 manager 的信息
  6. SELECT manager.*
  7. FROM employees worker, employees manager
  8. WHERE worker.last_name = 'Chen' AND worker.manager_id = manager.employee_id;
复制代码
内连接 VS 外连接


刚才上面的查询都是内连接
6.3 多表查询的实现

基本语法
  1. # 使用JOIN ON子句创建连接
  2. SELECT table1.column, table2.column,table3.column
  3. FROM table1
  4.         JOIN table2 ON table1 和 table2 的连接条件
  5.                 JOIN table3 ON table2 和 table3 的连接条件
复制代码
内连接(INNER JOIN)的实现


外连接(OUTER JOIN)的实现

UNION

UNION有两种查询,分别是UNION和UNION ALL
UNION ALL所需要的资源比UNION少,如果确定结果没有重复记录,建议使用UNION ALL,提高数据查询速度。
练习
  1. # 查询部门编号>90或邮箱包含a的员工信息
  2. # 直接查询
  3. SELECT * FROM employees e
  4. WHERE e.department_id > 90 OR e.email LIKE "%a%";
  5. # UNION查询
  6. SELECT * FROM employees e1
  7. WHERE e1.email LIKE "%a%"
  8. UNION
  9. SELECT * FROM employees e2
  10. WHERE e2.department_id > 90;
  11. # 查询中国用户中男性的信息以及美国用户中年男性的用户信息
  12. # 表t_chinamale 和 表 t_usmale
  13. SELECT id,cname FROM t_chinamale WHERE csex='男'
  14. UNION ALL
  15. SELECT id,tname FROM t_usmale WHERE tGender='male';
复制代码
6.4 7种SQL JOIN的实现

  1. # 还是拿员工表和部门表作为例子
  2. # 左上角 左外连接
  3. SELECT e.employee_id, e.last_name, department_name
  4. FROM employees e LEFT JOIN departments d
  5. ON e.department_id = d.department_id;
  6. # 右上角 右外连接
  7. SELECT e.employee_id, e.last_name, department_name
  8. FROM employees e RIGHT JOIN departments d
  9. ON e.department_id = d.department_id;
  10. # 中间图内连接
  11. SELECT e.employee_id, e.last_name, department_name
  12. FROM employees e JOIN departments d
  13. ON e.department_id = d.department_id;
  14. # 左下图 这个就是两个集合的并集用UNION就可以处理
  15. SELECT e.employee_id, e.last_name, department_name
  16. FROM employees e LEFT JOIN departments d
  17. ON e.department_id = d.department_id
  18. UNION
  19. SELECT e.employee_id, e.last_name, department_name
  20. FROM employees e RIGHT JOIN departments d
  21. ON e.department_id = d.department_id;
复制代码
其余四个需要一定的解释,但是拿出来说
先说左中图和右中图,两个是一致的只是最终的结果是相反的
现在以左中图作为例子,实质上结果是 A - A∩B,
  1. # 左中图  A - A∩B
  2. # 可以先查询出A的外连接
  3. SELECT e.employee_id, e.last_name, department_name
  4. FROM employees e LEFT JOIN departments d
  5. ON e.department_id = d.department_id
  6. WHERE d.department_id IS NULL; # 在这里需要删掉B为NULL的时候
复制代码
这里有的同学可能会误解为什么是判断B表的字段是不是NULL为什么不是A表的?
这里解释一下,JOIN之后的操作实质上就是从笛卡尔集中取出数据,那么在查询出A表的外连接的时候,表会变成什么样呢,可以一起来看看

可能有人会说,这里A表B表的字段都是NULL,为什么不判断B表的呢?
在这里我想说的是,这里尚硅谷给的例子比较特殊,用的是外键去判断,如果这里的条件不是用等值的外键去判断呢,假设A没有这个字段,是不是只有B才有这个字段,也就是说当前获取的集合里面只能通过B表去判断是否为NULL!!!
同理
  1. # 右中图 B - A∩B
  2. SELECT e.employee_id, e.last_name, department_name
  3. FROM employees e RIGHT JOIN departments d
  4. ON e.department_id = d.department_id
  5. WHERE e.department_id IS NULL; # 在这里需要删掉B为NULL的时候
复制代码
剩下的左下图就是两个的并集
  1. SELECT e.employee_id, e.last_name, department_name
  2. FROM employees e LEFT JOIN departments d
  3. ON e.department_id = d.department_id
  4. WHERE d.department_id IS NULL
  5. UNION
  6. SELECT e.employee_id, e.last_name, department_name
  7. FROM employees e RIGHT JOIN departments d
  8. ON e.department_id = d.department_id
  9. WHERE e.department_id IS NULL;
复制代码
6.5 SQL99的新特性

自然连接

自然连接就是NATURAL JOIN ,自然连接会自动匹配两张表的相同字段,然后进行等值连接
  1. # 正常内连接写法
  2. SELECT employee_id,last_name,department_name
  3. FROM employees e JOIN departments d
  4. ON e.`department_id` = d.`department_id`
  5. AND e.`manager_id` = d.`manager_id`;
  6. # 使用自然连接
  7. SELECT employee_id,last_name,department_name
  8. FROM employees e NATURAL JOIN departments d;
复制代码
USING连接

USING连接和自然连接很接近,自然连接时自动匹配所有相同字段,USING是指定一个相同字段
  1. # 内连接
  2. SELECT employee_id,last_name,department_name
  3. FROM employees e ,departments d
  4. WHERE e.department_id = d.department_id;
  5. # 使用USING后
  6. SELECT employee_id,last_name,department_name
  7. FROM employees e JOIN departments d
  8. USING (department_id);
复制代码
注:可以看出来内连接和刚才的等值连接很像,只是所使用的语法不同,其实从实质上两个可以理解成相同的,在SQL92规范中,内连接就是等值连接,而外连接只需要用+,但是MySQL不支持这种写法,现在的SQL99虽然写起来繁琐,但是比较好分辨。
  1. #左外连接
  2. SELECT last_name,department_name
  3. FROM employees ,departments
  4. WHERE employees.department_id = departments.department_id(+);
  5. #右外连接
  6. SELECT last_name,department_name
  7. FROM employees ,departments
  8. WHERE employees.department_id(+) = departments.department_id;
复制代码

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4