可变日期范围内的总金额
Sum Amounts That Fall Within Variable Date Ranges
我有两个 table 类似于下面的示例 table。 PAY
table 显示了员工的薪水和时间。 ENROLL
table 显示员工何时注册 'E'
以及他们后来何时终止 'T'
。因此,在这种情况下,员工从 3/1/14
注册到 5/31/14
,然后从 10/01/14
注册到 11/30/14
。
支付 table
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
注册table
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_END_DT
的 PAY_AMT
.例如,在这种情况下,我只想将 PAY_AMT
的 PAY_END_DT
归入 3/1/14
至 5/31/14
或 10/01/14
至 11/30/14
。所以,正确的结果是:
EMPLID SUM
00100001 830
我需要 运行 这个 SQL 用于很多不同的 EMPLID
s,其中一些可能有两个注册期,就像这个例子,而其他人可能有零、一、三个或多个注册期。
我曾考虑过使用 lead()
,但不太清楚在这种情况下如何使用它。我也考虑过使用 between...and...
但由于注册期的数量可能会有所不同,我不知道如何处理。
我不想使用 PL/SQL。
为了让事情变得更简单,下面是这两个 table 的模板:
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
)
你对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;
我有两个 table 类似于下面的示例 table。 PAY
table 显示了员工的薪水和时间。 ENROLL
table 显示员工何时注册 'E'
以及他们后来何时终止 'T'
。因此,在这种情况下,员工从 3/1/14
注册到 5/31/14
,然后从 10/01/14
注册到 11/30/14
。
支付 table
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
注册table
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_END_DT
的 PAY_AMT
.例如,在这种情况下,我只想将 PAY_AMT
的 PAY_END_DT
归入 3/1/14
至 5/31/14
或 10/01/14
至 11/30/14
。所以,正确的结果是:
EMPLID SUM
00100001 830
我需要 运行 这个 SQL 用于很多不同的 EMPLID
s,其中一些可能有两个注册期,就像这个例子,而其他人可能有零、一、三个或多个注册期。
我曾考虑过使用 lead()
,但不太清楚在这种情况下如何使用它。我也考虑过使用 between...and...
但由于注册期的数量可能会有所不同,我不知道如何处理。
我不想使用 PL/SQL。
为了让事情变得更简单,下面是这两个 table 的模板:
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
)
你对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;