web-dev-qa-db-ja.com

Oracle SQL-選択内で選択(同じテーブル上で!)

それ以外の方法を説明する方法がわからないので、私がすばやく達成しようとしていることを試して説明します。

ここには、すべての従業員のすべての雇用履歴を示すテーブルがあります。現在の投稿の「開始日」が必要です(「現在のフラグ」=「Y」)。それだけでなく、その前の投稿の「End_Date」が必要です(現在のフラグでフィルターし、終了日で並べ替え、一番上のフラグを取得します)。

とにかく、これが私のコードです:

SELECT "Gc_Staff_Number",
       "Start_Date",
       (SELECT "End_Date"
        FROM   "Employment_History"
        WHERE  "Current_Flag" != 'Y'
               AND ROWNUM = 1
               AND "Employee_Number" = "Employment_History"."Employee_Number"
        ORDER  BY "End_Date" ASC)
FROM   "Employment_History"
WHERE  "Current_Flag" = 'Y'

これを機能させる方法についての提案は素晴らしいでしょう、うまくいけば、上記が少し意味をなすでしょう-現時点で正直に言うと、実際にはうまくいかなくても、うーん、うんざりです。

(編集:ああ!私はこれを既存のシステムを照会するために書いています...なんらかの理由で、テーブルとフィールド名の周りにすべての愚かな二重引用符があります、ため息!)

8
Nick

これは、まさに分析が助けになるシナリオの一種です。

このテストデータを考えると、

SQL> select * from employment_history
  2  order by Gc_Staff_Number
  3             , start_date
  4  /

GC_STAFF_NUMBER START_DAT END_DATE  C
--------------- --------- --------- -
           1111 16-OCT-09           Y
           2222 08-MAR-08 26-MAY-09 N
           2222 12-DEC-09           Y
           3333 18-MAR-07 08-MAR-08 N
           3333 01-JUL-09 21-MAR-09 N
           3333 30-JUL-10           Y

6 rows selected.

SQL> 

分析LAG()関数を使用したインラインビューが正しい答えを提供します。

SQL> select Gc_Staff_Number
  2             , start_date
  3             , prev_end_date
  4  from   (
  5      select Gc_Staff_Number
  6             , start_date
  7             , lag (end_date) over (partition by Gc_Staff_Number
  8                                    order by start_date )
  9                  as prev_end_date
 10             , current_flag
 11      from employment_history
 12  )
 13  where current_flag = 'Y'
 14  /

GC_STAFF_NUMBER START_DAT PREV_END_
--------------- --------- ---------
           1111 16-OCT-09
           2222 12-DEC-09 26-MAY-09
           3333 30-JUL-10 21-MAR-09

SQL>

インラインビューは、正しい結果を得るために重要です。それ以外の場合、CURRENT_FLAGのフィルターは前の行を削除します。

10
APC
SELECT "Gc_Staff_Number",
       "Start_Date",
       (SELECT "End_Date"
        FROM   "Employment_History"
        WHERE  "Current_Flag" != 'Y'
               AND ROWNUM = 1
               AND "Employee_Number" = "Employment_History"."Employee_Number"
        ORDER  BY "End_Date" ASC)
FROM   "Employment_History"
WHERE  "Current_Flag" = 'Y'

参考までに、この場合、ROWNUM = 1はORDER BYの前に評価されるため、内部クエリは(最大で)1つのレコードの総計をソートします。

特定の従業員の最も早いend_date(current_flag <> 'Y')を本当に探している場合、これが探しているものですか?

SELECT "Gc_Staff_Number",
       "Start_Date",
       eh.end_date
  FROM "Employment_History" eh
       LEFT OUTER JOIN -- in case the current record is the only record...
       (SELECT "Employee_Number"
             , MIN("End_Date") as end_date
          FROM "Employment_History"
         WHERE "Current_Flag" != 'Y'
         GROUP BY "Employee_Number" 
       ) emp_end_date
          ON eh."Employee_Number" = emp_end_date."Employee_Number"
 WHERE eh."Current_Flag" = 'Y'
2

私は引用符で少し混乱していますが、以下はあなたのために働くはずです:

SELECT "Gc_Staff_Number",
       "Start_Date", x.end_date
FROM   "Employment_History" eh,
(SELECT "End_Date"
        FROM   "Employment_History"
        WHERE  "Current_Flag" != 'Y'
               AND ROWNUM = 1
               AND "Employee_Number" = eh.Employee_Number
        ORDER  BY "End_Date" ASC) x
WHERE  "Current_Flag" = 'Y'
2
El Guapo
SELECT eh."Gc_Staff_Number",
       eh."Start_Date",
       MAX(eh2."End_Date") AS "End_Date"
FROM   "Employment_History" eh
LEFT JOIN  "Employment_History" eh2
ON eh."Employee_Number" = eh2."Employee_Number" and eh2."Current_Flag" != 'Y'
WHERE  eh."Current_Flag" = 'Y' 
GROUP BY eh."Gc_Staff_Number",
       eh."Start_Date
2
Martin Smith

これは私が LAG関数 を使用するものです:

SELECT eh.gc_staff_number,
       eh.start_date,
       LAG(eh.end_date) OVER (PARTITION BY eh.gc_staff_number
                                  ORDER BY eh.end_date) AS prev_end_date
  FROM EMPLOYMENT_HISTORY eh
 WHERE eh.current_flag = 'Y'

行を先読みしたい場合は、 LEAD関数 を使用します。

互換性:

私の知る限り、これは9i +でサポートされていますが、ドキュメントの主張のように8iがサポートされていることは確認していません。

LEADとLAGは最終的にANSIですが、現在サポートされているのはOracleと PostgreSQL v8.4 + のみです。

1
OMG Ponies

基本的に、あなたがしなければならないのは

select ..., (select ... from ... where ...) as ..., ..., from ... where ...

例えば。 (select ... from ... where)は、対応するデータに置き換えたい場所に挿入できます。

私は他の例(それぞれが本当に素晴らしいとしても:))を初心者にとって理解するのが少し複雑であることを知っています(私のように:p)。

0
xoxel