Oracle外连接未按预期工作

时间:2013-08-05 14:47:46

标签: sql oracle join outer-join

我有以下查询:

select *
from   per_all_assignments_f paaf,
       pay_all_payrolls_f    payr
where  sysdate between paaf.effective_start_date and paaf.effective_end_date
and    paaf.assignment_type in ('E', 'C')
and    paaf.primary_flag = 'Y'
and    payr.payroll_id (+) = paaf.payroll_id
and    nvl(payr.attribute1 (+), '$XXX$') in ('TINT')
and    paaf.effective_start_date between nvl(payr.effective_start_date (+), to_date('01/01/1000', 'dd/mm/yyyy')) 
                                     and nvl(payr.effective_end_date   (+), to_date('31/12/4712', 'dd/mm/yyyy'))

由于TINT工资单上有7个,我希望能够获得7个员工的任务。但是它返回10035行,其中7行具有工资表的详细信息,其他具有空白数据。所以外部联接没有像我预期的那样工作。我做错了什么?

2 个答案:

答案 0 :(得分:1)

尝试使用标准连接语法编写此代码,将第二个表上的条件移动到on子句中:

select *
from   per_all_assignments_f paaf left outer
       pay_all_payrolls_f    payr
       on payr.payroll_id = paaf.payroll_id and
          nvl(payr.attribute1, '$XXX$') in ('TINT') and
          paaf.effective_start_date between nvl(payr.effective_start_date,
                                                to_date('01/01/1000', 'dd/mm/yyyy')) 
                                     and nvl(payr.effective_end_date,
                                             to_date('31/12/4712', 'dd/mm/yyyy'))
where paaf.assignment_type in ('E', 'C') and
      paaf.primary_flag = 'Y' and
      sysdate between paaf.effective_start_date and paaf.effective_end_date;

答案 1 :(得分:1)

听起来你真正想要的是INNER加入。放下(+),看看你是否找回了你想要的东西。另外,@ GordonLinoff提出了一个很好的建议 - 使用ANSI连接语法很舒服,这种语法比旧式“将所有条件放在WHERE子句中然后尝试解决它”更具表现力和更易理解

以下是我使用ANSI标准连接语法重写此查询的方法:

SELECT *
  FROM PER_ALL_ASSIGNMENTS_F paaf
  INNER JOIN PAY_ALL_PAYROLLS_F payr
    ON payr.PAYROLL_ID = paaf.PAYROLL_ID
  WHERE SYSDATE BETWEEN paaf.EFFECTIVE_START_DATE
                    AND paaf.EFFECTIVE_END_DATE AND
        paaf.ASSIGNMENT_TYPE IN ('E', 'C') AND
        paaf.PRIMARY_FLAG = 'Y' AND
        payr.ATTRIBUTE1 = 'TINT' AND
        paaf.EFFECTIVE_START_DATE BETWEEN NVL(payr.EFFECTIVE_START_DATE, TO_DATE('01/01/1000', 'DD/MM/YYYY')) 
                                      AND NVL(payr.EFFECTIVE_END_DATE, TO_DATE('31/12/4712', 'DD/MM/YYYY'))

另一个小问题。我注意到你正在使用BETWEEN和日期值,这可能会有问题。比方说,例如,你在PER_ALL_ASSIGNMENTS_F的某一行有一个EFFECTIVE_START的01-JAN-2013和EFFECTIVE_END_DATE 30-JUN-2013,让我们进一步说当前的日期和时间是30-JUN-2013上午07:02:04给定这些数据值,PER_ALL_ASSIGNMENTS_F中的这一行将被选中 NOT ,尽管您可能期望它。问题是,当DATE值中填写的唯一字段是日,月和年时,则小时,分钟和秒默认为零 - 因此结束日期确实 30- JUN-2013在00:00:00,即当前日期/时间30-JUN-2013之间的07:02:04 AM,因此日期比较导致该行被忽略。我不知道你的数据库中是如何填充EFFECTIVE_END_DATE字段的 - 希望它们完全填满,例如30-JUN-2013 23:59:59 - 但如果不是,你可能需要使你的日期比较像

TRUNC(SYSDATE) BETWEEN paaf.EFFECTIVE_START_DATE
                   AND paaf.EFFECTIVE_END_DATE

SYSDATE BETWEEN paaf.EFFECTIVE_START_DATE
            AND paaf.EFFECTIVE_END_DATE + INTERVAL '1' DAY - INTERVAL '1' SECOND

(前者可能是更好的选择,因为后一种形式将排除使用可能存在的任何非基于函数的索引(EFFECTIVE_START_DATE,EFFECTIVE_END_DATE)。

分享并享受。