问题
现有表EMP和DEPT如下:
EMP
EMPID EMPNAME DEPTID
1 张三 1
2 李四 2
3 王五 2
4 赵六 2
5 孙七 3
DEPT
DEPTID DEPTNAME
1 开发
2 测试
3 需求
4 销售
现在要看开发部门的人员情况。
这个问题只需以EMP.DEPTID等于DEPT.DEPTID为连接条件来连接两张表。一般来说,跨表查询有两种实现方法:ANSI SQL和dialect SQL
方法1
ANSI SQL,使用JOIN…ON…子句。SQL statement如下:
SELECT EMP.* FROM EMP
JOIN DEPT
ON EMP.DEPTID = DEPT.DEPTID
WHERE DEPT.DEPTID = 1
方法2
Dialect SQL,把连接条件和过滤条件都放在WHERE子句里。SQL statement如下:
SELECT EMP.* FROM EMP, DEPT
WHERE EMP.DEPTID = DEPT.DEPTID AND DEPT.DEPTID = 1
这两种方法本身都没有问题。观察这两个SQL语句可见,二者的区别在于前者把连接条件和过滤条件分开了,而后者没有分开。那么问题就来了,连接条件和过滤条件需要分开吗?在ANSI写法下,如果不分开会怎么样?例如下面的SQL statement:
方法3
SELECT EMP.* FROM EMP
JOIN DEPT
ON EMP.DEPTID = DEPT.DEPTID AND DEPT.DEPTID = 1
虽然“DEPT.DEPTID = 1”并不是连接条件,但是这里把它放到ON子句里,也能得到正确的结果。那么WHERE和ON到底有何不同呢?
分析
我上网查了一些资料,自己也做了一些试验。目前得到的结论为,对于内连接(inner join),二者并无不同(至少从结果上看,至于效率就不清楚了)。所以上面的例子中,这三种写法都OK。当然,把过滤条件放在ON子句里,可读性会差很多。
对于外连接,二者还是确有不同的。比如,我要得到某个部门(如开发)的人数,由于有的部门可能没有员工,所以这里必须用外连接。SQL statement如下:
方法一
SELECT DEPT.DEPTID, DEPT.DEPTNAME, COUNT(EMP.EMPID) AS EMPNUMBER
FROM DEPT
LEFT JOIN EMP
ON EMP.DEPTID=DEPT.DEPTID
WHERE DEPTNAME = '开发'
GROUP BY DEPT.DEPTID, DEPT.DEPTNAME
结果如下:
DEPTID DEPTNAME EMPNUMBER
1 开发 1
这里连接条件和过滤条件就不能混用,如果把过滤条件也放到连接条件里,SQL statement如下:
方法二
SELECT DEPT.DEPTID, DEPT.DEPTNAME, COUNT(EMP.EMPID) AS EMPNUMBER
FROM DEPT
LEFT JOIN EMP
ON EMP.DEPTID=DEPT.DEPTID AND DEPTNAME = '开发'
GROUP BY DEPT.DEPTID, DEPT.DEPTNAME
方法二的实际结果跟预期结果有所不同,如下:
DEPTID DEPTNAME EMPNUMBER
1 开发 1
2 测试 0
3 需求 0
4 销售 0
要了解为何两个SQL语句的结果不同,就要明白SQL执行的顺序。如下:
1) 用笛卡尔乘积连接两张表;
2) 用ON条件过滤结果集;
3) LEFT、RIGHT、FULL条件起作用;
4) WHERE条件过滤结果集;
5) GROUP BY起作用。
下面分别列出两种方法中每一步执行的结果。
方法一
1) 用笛卡尔乘积连接两张表;
DEPTID DEPTNAME EMPID EMPNAME DEPTID
1 开发 1 张三 1
1 开发 2 李四 2
1 开发 3 王五 2
1 开发 4 赵六 2
1 开发 5 孙七 3
2 测试 1 张三 1
2 测试 2 李四 2
2 测试 3 王五 2
2 测试 4 赵六 2
2 测试 5 孙七 3
3 需求 1 张三 1
3 需求 2 李四 2
3 需求 3 王五 2
3 需求 4 赵六 2
3 需求 5 孙七 3
4 销售 1 张三 1
4 销售 2 李四 2
4 销售 3 王五 2
4 销售 4 赵六 2
4 销售 5 孙七 3
2) 用ON条件过滤结果集;
DEPTID DEPTNAME EMPID EMPNAME DEPTID
1 开发 1 张三 1
2 测试 2 李四 2
3 需求 5 孙七 3
3) LEFT、RIGHT、FULL条件起作用;
DEPTID DEPTNAME EMPID EMPNAME DEPTID
1 开发 1 张三 1
2 测试 2 李四 2
3 需求 5 孙七 3
4 销售 NULL NULL NULL
4) WHERE条件过滤结果集;
DEPTID DEPTNAME EMPID EMPNAME DEPTID
1 开发 1 张三 1
5) GROUP BY起作用。
DEPTID DEPTNAME EMPNUMBER
1 开发 1
方法二
1) 用笛卡尔乘积连接两张表;同方法一
2) 用ON条件过滤结果集;
DEPTID DEPTNAME EMPID EMPNAME DEPTID
1 开发 1 张三 1
3) LEFT、RIGHT、FULL条件起作用;
DEPTID DEPTNAME EMPID EMPNAME DEPTID
1 开发 1 张三 1
2 测试 NULL NULL NULL
3 需求 NULL NULL NULL
4 销售 NULL NULL NULL
4) WHERE条件过滤结果集;无WHERE过滤条件
5) GROUP BY起作用。
DEPTID DEPTNAME EMPNUMBER
1 开发 1
2 测试 0
3 需求 0
4 销售 0
结论
对于外连接,一定注意不要把连接条件和过滤条件混淆了。其实,即使对于内连接,把连接条件和过滤条件分开来,对于可读性而言也很有好处。总而言之,推荐大家在跨表查询时,使用标准SQL写法(JOIN…ON…),并且把连接条件和过滤条件严格分开来。
sql JOIN ON VS WHERE
猜你喜欢
转载自jipengyun2008.iteye.com/blog/1465215
今日推荐
周排行