为什么ON条款中的条件不起作用?

时间:2017-10-03 13:14:00

标签: sql postgresql left-join

我有两个表格,我想要只在 main_sys 中加入行,其中curr_flag = 1到 integrated_sys 。这些查询返回不同的行,我无法弄清楚原因。

查看REERYESTER查询结果:http://rextester.com/YYR54058

QUERY 1 - curr_flag filter is in WHERE clause
select 
    * 
from 
    main_sys m
    left join integrated_sys i  on (m.master_id_sysa = i.master_id_sysa 
                                    or m.master_id_sysb = i.master_id_sysb)
where
    m.curr_flag = 1


QUERY 2 - curr_flag filter is in ON clause
select 
    * 
from 
    main_sys m
    left join integrated_sys i  on (   (
                                       m.master_id_sysa = i.master_id_sysa 
                                       or m.master_id_sysb = i.master_id_sysb
                                       ) 
                                   and m.curr_flag = 1
                                   )

表A: main_sys 包含位置的历史记录。

| hist_id | master_id_sysA | master_id_sysB | loc_desc    | curr_flag | eff_start_dt | eff_end_dt |
|---------|----------------|----------------|-------------|-----------|--------------|------------|
| 14009   | 1234           | 1234           | Detroit, MI | 1         | 7/2/2017     | 1/1/9999   |
| 14010   | 1234           | 1234           | Detroit, MI | 0         | 1/6/2017     | 7/1/2017   |
| 14011   | 1234           | 1234           | Detroit, MI | 0         | 9/2/2016     | 1/5/2017   |
| 14012   | 1234           | 1234           | Detroit, MI | 0         | 7/23/2016    | 9/1/2016   |
| 14013   | 1234           | 1234           | Detroit, MI | 0         | 5/31/2015    | 7/22/2016  |
| 90088   | 6655           | 6655           | Dover, DE   | 1         | 6/2/2015     | 6/21/2015  |
| 90087   | 6655           | 6655           | Dover, DE   | 0         | 6/1/2015     | 6/1/2015   |
| 90086   | 6655           | 6655           | Dover, DE   | 0         | 5/31/2015    | 5/31/2015  |
| 14413   | 8877           | NULL           | NULL        | 1         | 9/2/2017     | 12/31/9999 |
| 14412   | 8877           | 877            | Austin, TX  | 0         | 8/3/2017     | 9/1/2017   |
| 14411   | 8877           | NULL           | NULL        | 0         | 6/19/2017    | 8/2/2017   |
| 14410   | 8877           | 877            | NULL        | 0         | 2/18/2017    | 6/18/2017  |
| 14409   | 8877           | 877            | Austin, TX  | 0         | 2/16/2017    | 2/17/2017  |
| 14145   | 9595           | 9595           | Boston, MA  | 1         | 9/9/2006     | 10/10/2014 |
| 39014   | 9987           | 9987           | Atlanta, GA | 1         | 6/5/2017     | 1/1/9999   |
| 39013   | 9987           | 9987           | Atlanta, GA | 0         | 11/1/2016    | 6/4/2017   |
| 39012   | 9987           | 9987           | Atlanta, GA | 0         | 9/23/2016    | 10/31/2016 |
| 39011   | 9987           | 9987           | Atlanta, GA | 0         | 7/6/2016     | 9/22/2016  |
| 39010   | 9987           | 9987           | Atlanta, GA | 0         | 1/6/2016     | 7/5/2016   |

表B - integrated_sys 表包含每个位置的当前记录。

| loc_name       | master_id_sysA | master_id_sysB |
|----------------|----------------|----------------|
| Detroit, MI    | 1234           | 1234           |
| Atlanta, GA    | 9987           | 9987           |
| Dover, DE      | 6655           | 6655           |
| Boston, MA     | NULL           | 9595           |
| Tempe, AZ      | NULL           | 55             |
| Seattle, OR    | NULL           | 95             |
| Des Moines, IO | NULL           | 1478           |
| Bismarck, SD   | NULL           | 1515           |

这个问题解释了这种情况,但我仍然不知道为什么ON子句查询返回curr_flag为0的行: Why and when a LEFT JOIN with condition in WHERE clause is not equivalent to the same LEFT JOIN in ON?

2 个答案:

答案 0 :(得分:1)

如果LEFT JOINLEFT JOIN条件的一部分,那么它不会用于从左表中选择行,只能从右表中选择。尽管ON后面有任何条件,WHERE只是保留左表中的所有输入行。因此,如果您需要过滤左表的数据,那么您应该在index子句(您的第一个查询)后面写下这样的条件。

答案 1 :(得分:1)

因为它们在逻辑上是不同的。

查询1 - 从左表中选择curr_flag = 1的所有记录,当m.master_id_sysa = i.master_id_sysa or m.master_id_sysb = i.master_id_sysb子句为真时保留右表中的所有记录 - > ON()

查询2 - 从左表中选择所有记录,当(m.master_id_sysa = i.master_id_sysa or m.master_id_sysb = i.master_id_sysb) AND m.curr_flag = 1子句为真时保留右表中的所有记录 - > ON()

编辑:为了澄清 - 左连接的LEFT子句不会过滤RIGHT表中的记录,它只过滤SourceMigration表。