sql JOIN ON VS WHERE

问题
现有表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…),并且把连接条件和过滤条件严格分开来。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值