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'))

もう1つの小さな問題。問題が発生する可能性がある日付値で BETWEEN を使用していることに気付きました。たとえば、PER_ALL_ASSIGNMENTS_F のある行で EFFECTIVE_START_DATE が 01-JAN-2013 で、EFFECTIVE_END_DATE が 30-JUN-2013 であるとします。さらに、現在の日時が 30-JUN-2013 であるとします。午前 07:02:04。これらのデータ値が与えられた場合、PER_ALL_ASSIGNMENTS_F からのこの行は選択されませんが、そうなると予想されるかもしれません。問題は、DATE 値に入力されるフィールドが日、月、年のみの場合、時、分、秒がデフォルトでゼロになることです。したがって、終了日は実際にはこれは、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

2 番目のテーブルの条件を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 に答える