属于可变日期范围的总和金额

时间:2015-04-20 16:53:48

标签: sql oracle oracle11g

我有两个类似于下面的示例表的表。 PAY表显示员工的薪酬和时间。 ENROLL表显示员工注册的时间'E'以及之后何时终止'T'。因此,在这种情况下,员工从3/1/14注册到5/31/14,然后再次从10/01/14注册到11/30/14

支付表

EMPLID      PAY_END_DT    PAY_AMT
00100001    31-JAN-14     110
00100001    28-FEB-14     120
00100001    31-MAR-14     130     <-- should be included in SUM
00100001    30-APR-14     140     <-- should be included in SUM
00100001    31-MAY-14     150     <-- should be included in SUM
00100001    30-JUN-14     160
00100001    31-JUL-14     170
00100001    31-AUG-14     180
00100001    30-SEP-14     190
00100001    31-OCT-14     200     <-- should be included in SUM
00100001    30-NOV-14     210     <-- should be included in SUM
00100001    31-DEC-14     220

ENROLL表

EMPLID      EFFDT       STATUS
00100001    01-MAR-14   E
00100001    31-MAY-14   T
00100001    01-OCT-14   E
00100001    30-NOV-14   T

我想要的是一个SQL,它会对PAY_AMT列求和,但仅适用于在注册员工时发生PAY_AMTPAY_END_DT的{​​{1}}。例如,在这种情况下,我只想将PAY_AMT的{​​{1}}与PAY_END_DT3/1/145/31/14 10/01/14内的11/30/14相加{1}}。所以,正确的结果将是:

EMPLID    SUM
00100001  830

我需要为许多不同的EMPLID运行此SQL,其中一些可能有两个注册周期,如此示例,其他可能有零个,一个,三个或更多注册周期。

我曾考虑使用lead(),但在这种情况下无法弄清楚如何使用它。我还考虑过使用between...and...,但由于注册时间可能会有所不同,因此我不知道如何处理。

我不想使用PL / SQL。

为了使事情变得更容易,下面是这两个表的模板:

WITH 
PAY AS(
SELECT '00100001' AS EMPLID, TO_DATE('2014-01-31', 'YYYY-MM-DD') AS PAY_END_DT, 110.00 AS PAY_AMT FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-02-28', 'YYYY-MM-DD'), 120.00 AS PAY_AMT FROM DUAL
UNION ALL
--SUM column would include this PAY_AMT
SELECT '00100001', TO_DATE('2014-03-31', 'YYYY-MM-DD'), 130.00 AS PAY_AMT FROM DUAL
UNION ALL
--SUM column would include this PAY_AMT
SELECT '00100001', TO_DATE('2014-04-30', 'YYYY-MM-DD'), 140.00 AS PAY_AMT FROM DUAL
UNION ALL
--SUM column would include this PAY_AMT
SELECT '00100001', TO_DATE('2014-05-31', 'YYYY-MM-DD'), 150.00 AS PAY_AMT FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-06-30', 'YYYY-MM-DD'), 160.00 AS PAY_AMT FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-07-31', 'YYYY-MM-DD'), 170.00 AS PAY_AMT FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-08-31', 'YYYY-MM-DD'), 180.00 AS PAY_AMT FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-09-30', 'YYYY-MM-DD'), 190.00 AS PAY_AMT FROM DUAL
UNION ALL
--SUM column would include this PAY_AMT
SELECT '00100001', TO_DATE('2014-10-31', 'YYYY-MM-DD'), 200.00 AS PAY_AMT FROM DUAL
UNION ALL
--SUM column would include this PAY_AMT
SELECT '00100001', TO_DATE('2014-11-30', 'YYYY-MM-DD'), 210.00 AS PAY_AMT FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-12-31', 'YYYY-MM-DD'), 220.00 AS PAY_AMT FROM DUAL
),
ENROLL AS (
SELECT '00100001' AS EMPLID, TO_DATE('2014-03-01', 'YYYY-MM-DD') AS EFFDT, 'E' AS STATUS FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-05-31', 'YYYY-MM-DD'), 'T' FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-10-01', 'YYYY-MM-DD'), 'E' FROM DUAL
UNION ALL
SELECT '00100001', TO_DATE('2014-11-30', 'YYYY-MM-DD'), 'T' FROM DUAL
)

1 个答案:

答案 0 :(得分:3)

您对lead()的猜测是正确的,解决方案非常简单:

with pay as (...),
     enroll as (...)
select pay.emplid, sum(pay_amt) 
    from pay, 
         (select emplid, effdt effdt_start, status, 
                 lead(effdt, 1) over (partition by emplid order by effdt) effdt_end
            from enroll) enr
   where enr.emplid = pay.emplid
     and enr.status = 'E'
     and pay.pay_end_dt between enr.effdt_start and enr.effdt_end
   group by pay.emplid;