1. 多表连接的问题
SELECT employee_id,department_name FROM employees,departments;#查询出2889条
SELECT COUNT(employee_id) FROM employees; #输出107行 SELECT COUNT(department_id)FROM departments; #输出27行 SELECT 107*27 FROM dual;//2889
由此可见,查询到结果每一个employee_id都没有选择的重复了departments表中所有的department_name
我们把上述多表查询中出现的问题称为:笛卡尔积的错误。
笛卡尔积(或交叉连接)的理解
笛卡尔乘积是一个数学运算。假设我有两个集合X 和Y,那么X和Y的笛卡尔积就是X和Y的所有可能
组合,也就是第一个对象来自于X,第二个对象来自于Y的所有可能。组合的个数即为两个集合中元素
个数的乘积数。
SQL92中,笛卡尔积也称为 交叉连接 ,英文是 CROSS JOIN 。在 SQL99 中也是使用 CROSS JOIN表示交叉连接。它的作用就是可以把任意表进行连接,即使这两张表不相关。在MySQL中如下情况会出现笛卡尔积。
#查询员工姓名和所在部门名称 SELECT last_name,department_name FROM employees,departments; SELECT last_name,department_name FROM employees CROSS JOIN departments;; SELECT last_name,department_name FROM employees INNER JOIN departments; SELECT last_name,department_name FROM employees JOIN departments;
案例分析与问题解决
笛卡尔积的错误会在下面条件下产生:
省略多个表的连接条件(或关联条件)
连接条件(或关联条件)无效
所有表中的所有行互相连接
为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件。
加入连接条件后,查询语法:
SELECT table1.column, table2.column FROM table1, table2 WHERE table1.column1 = table2.column2; #连接条件
在 WHERE子句中写入连接条件。
正确写法:
#案例:查询员工的姓名及其部门名称 SELECT last_name, department_name FROM employees, departments WHERE employees.department_id = departments.department_id;
执行代码后,一共查询到106条数据,且没有产生笛卡尔积(交叉连接)的错误。
在表中有相同列时,在列名之前加上表名前缀。
补充:表的别名
1)可以给表起别名,在SELECT和WHERE中使用表的别名
SELECT emp.`employee_id`,dept.`department_id`,emp.`department_id` FROM employees emp,departments dept WHERE emp.`department_id` = dept.`department_id`
2)如果给表起了别名,一旦在SELECT和WHERE中使用表的别名,则必须使用表的别名,而不能再用 表的原名
3)连接 n个表,至少需要n-1个连接条件。
2. 多表查询分类讲解
2.1等值连接 vs 非等值连接
等值连接
SELECT employees.last_name, departments.department_name,employees.department_id FROM employees, departments WHERE employees.department_id = departments.department_id;
非等值连接
SELECT e.last_name, e.salary, j.grade_level FROM employees e, job_grades j WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal;
2.2自连接 vs 非自连接
当table1和table2本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。然后两个表再进行内连接,外连接等查询。
2.2内连接 vs 外连接
除了查询满足条件的记录以外,外连接还可以查询某一方不满足条件的记录。
内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行
外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的
行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。
如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表 。
如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表 。
SQL92:使用(+)创建连接
在 SQL92 中采用(+)代表从表所在的位置。即左或右外连接中,(+) 表示哪个是从表。Oracle 对 SQL92 支持较好,而 MySQL 则不支持 SQL92 的外连接。
#左外连接 SELECT last_name,department_name FROM employees ,departments WHERE employees.department_id = departments.department_id(+); #右外连接 SELECT last_name,department_name FROM employees ,departments WHERE employees.department_id(+) = departments.department_id;
SQL99:中使用JOIN .. ON
在 SQL92 中采用JOIN .. ON的方式实现多表的查询。这种方式也能解决外连接的问题。MySQL是支持此种方式的。例如:
# 左外连接: SELECT last_name,department_name FROM employees e LEFT JOIN departments d ON e.`department_id` = d.`department_id`; #右外连接: SELECT last_name,department_name FROM employees e RIGHT OUTER JOIN departments d ON e.`department_id` = d.`department_id`;