4

従業員がアクティブ/非アクティブになった日付のリストを含むテーブルがあり、特定の日付範囲内で従業員がアクティブであった週をカウントしたいと考えています。

したがって、テーブル (ps_job) の値は次のようになります。

EMPLID     EFFDT       HR_STATUS
------     -----       ------
1000       01-Jul-11   A
1000       01-Sep-11   I
1000       01-Jan-12   A
1000       01-Mar-12   I
1000       01-Sep-12   A

このクエリでは、この emplid が 2011 年 7 月 1 日から 2012 年 12 月 31 日までアクティブだった週数を表示する必要があります。

望ましい結果セットは次のようになります。

EMPLID     WEEKS_ACTIVE
------     ------------
1000       35

以下の SQL の結果を追加して、35 という数字を取得しました。

SELECT (NEXT_DAY('01-Sep-11','SUNDAY') - NEXT_DAY('01-Jul-11','SUNDAY'))/7 WEEKS_ACTIVE FROM DUAL;
SELECT (NEXT_DAY('01-Mar-12','SUNDAY') - NEXT_DAY('01-Jan-12','SUNDAY'))/7 WEEKS_ACTIVE FROM DUAL;
SELECT (NEXT_DAY('31-Dec-12','SUNDAY') - NEXT_DAY('01-Sep-12','SUNDAY'))/7 WEEKS_ACTIVE FROM DUAL;

問題は、特定の日付範囲内のすべての従業員のすべての行を調べて、各 emplid とアクティブな週数を返す単一のクエリ ステートメントを作成する方法を理解できないようです。ユーザーが実行できる PeopleSoft クエリに転送できるように、PL/SQL ではなく基本的な SQL を使用したいと考えていますが、必要に応じて Oracle SQL Developer を使用してユーザーのために SQL を実行したいと考えています。

データベース: Oracle Database 11g Enterprise Edition リリース 11.2.0.3.0 - 64 ビット製品

4

3 に答える 3

0

顧客が大まかな見積もりだけを求めている場合は、各スティントの日数を 7 で割って四捨五入します。

秘訣は、アクティブな日付と対応する非アクティブな日付を並べることです。これを行うための最良の方法は、アクティブな日付と非アクティブな日付を別々に選択し、日付ごとにランク付けしてから、それらをランク付けして結合することEmplIDです。ROW_NUMBER()分析関数は、この状況でランク付けするための最良の方法です。

WITH
  EmpActive AS (
    SELECT
        EmplID,
        EffDt,
        ROW_NUMBER() OVER (PARTITION BY EmplID ORDER BY EffDt NULLS LAST) DtRank
      FROM ps_job
      WHERE HR_Status = 'A'
  ),
  EmpInactive AS (
   SELECT
      EmplID,
      EffDt,
      ROW_NUMBER() OVER (PARTITION BY EmplID ORDER BY EffDt NULLS LAST) DtRank
    FROM ps_job
    WHERE HR_Status = 'I'
  )
SELECT
  EmpActive.EmplID,
  EmpActive.EffDt AS ActiveDate,
  EmpInactive.EffDt AS InactiveDate,
  ROUND((NVL(EmpInactive.EffDt, TRUNC(SYSDATE)) - EmpActive.EffDt) / 7) AS WeeksActive
FROM EmpActive
LEFT JOIN EmpInactive ON
    EmpActive.EmplID = EmpInactive.EmplID AND
    EmpActive.DtRank = EmpInactive.DtRank

の 3 番目のギグにEmplID = 1000はアクティブな日付がありますが、非アクティブな日付はありません。したがって、2 つのサブクエリ間の順序と左側の結合ですNULLS LASTROW_NUMBER

ここでは「日 / 7」の計算を使用しました。顧客からの返信があったときに、必要なものを代用できます。対応する非アクティブな日付がない場合、クエリは現在の日付を使用することに注意してください。

これの SQLFiddle がありますhere

于 2013-05-08T17:58:54.007 に答える
0

以下は、あなたがやろうとしていることに対してうまくいくはずです。NVLステートメントで終了日をハードコーディングする必要がありました

SELECT emplid,
       hr_status,
       ROUND(SUM(end_date - start_date)/7) num_weeks
  FROM (SELECT emplid,
               hr_status,
               effdt start_date,
               NVL(LEAD(effdt) OVER (PARTITION BY emplid ORDER BY effdt), 
                                        TO_DATE('12312012','MMDDYYYY')) end_date
          FROM ps_job
       )
 WHERE hr_status = 'A'
 GROUP BY emplid,
          hr_status
 ORDER BY emplid

内部クエリは、テーブルから従業員と HR ステータス情報を取得し、effdt 列を開始日として使用し、LEAD 分析関数を使用してテーブルから次の effdt 日付値を取得します。これは、次のステータスの開始を示します。現在の行の end_date になります。LEAD 関数が NULL を返す場合、必要な終了日 (2012 年 12 月 31 日) が割り当てられます。次に out ステートメントは、結果セットを有効な HR ステータスを持つレコードに限定し、週を計算します。

于 2013-05-08T19:01:30.877 に答える
0

ここでleadは、サブクエリで使用して次の日付を取得し、外側のクエリで間隔を合計しています。

with q as (
    select EMPLID, EFFDT, HR_STATUS
        , lead (EFFDT, 1) over (partition by EMPLID order by EFFDT) as NEXT_EFFDT
    from ps_job
    order by EMPLID, EFFDT
)
select EMPLID
    , trunc(sum((trunc(coalesce(NEXT_EFFDT, current_timestamp)) - trunc(EFFDT)) / 7)) as WEEKS_ACTIVE
from q
where HR_STATUS = 'A'
group by EMPLID;

この関数は、一致するレコードcoalesceが見つからない場合 (従業員が現在の従業員) にシステム日付を取得します。Iそれがあなたの仕様であれば、年末に置き換えることができます。

エントリが A/I/A/I などの順序で並べられていることを確認するための厳密なテストは行っていないことに注意してください。そのため、データに必要なことがわかっている場合は、そのようなチェックを追加することをお勧めします。

SQL Fiddleでこれを自由に試してください。

于 2013-05-08T19:36:52.433 に答える