0

我有以下查询:

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 行包含工资表的详细信息,其他行包含空白数据。所以外部连接没有像我预期的那样工作。我究竟做错了什么?

4

2 回答 2

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_DATE 为 2013 年 1 月 1 日,EFFECTIVE_END_DATE 为 2013 年 6 月 30 日,我们进一步说当前日期和时间是 2013 年 6 月 30 日在上午 07:02:04。鉴于这些数据值,将不会选择PER_ALL_ASSIGNMENTS_F 中的这一行,尽管您可能期望它会被选中。问题是,当 DATE 值上填写的唯一字段是日、月和年时,小时、分钟和秒默认为零 - 因此结束日期确实是2013 年 6 月 30 日 00:00:00,早于 2013 年 6 月 30 日上午 07:02:04 的当前日期/时间,因此日期比较会导致该行被忽略。我不知道 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) 上的任何基于非函数的索引。

分享和享受。

于 2013-08-05T16:27:07.720 回答
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;
于 2013-08-05T14:54:17.127 回答