如何解决Oracle:根据过去6个月的时间间隔为每行计算count
我有以下数据(数据可从2017年至今)
SELECT * FROM TABLE1 WHERE DATE > TO_DATE('01/01/2019','MM/DD/YYYY')
Emp_ID Date Vehicle_ID Working_Hours
1005 01/01/2019 X500 7
1005 01/02/2019 X500 6
1005 01/03/2019 X700 7
1005 01/04/2019 X500 5
1005 01/05/2019 X700 7
1005 01/06/2019 X500 7
1006 01/01/2019 X500 7
1006 01/02/2019 X500 6
1006 01/03/2019 X700 7
1006 01/04/2019 X500 5
1006 01/05/2019 X700 7
1006 01/06/2019 X500 7
我需要计算两列。 LAST_6M_UNIQ_Vehicle_Count ==>该员工最近(过去)6个月的唯一车辆ID计数 LAST_6M_Vehicle_Count ==>该雇员在过去6个月内所有车辆ID的计数 注意:从日期列开始的过去6个月
预期输出:
Emp_ID Date Vehicle_ID Working_Hours LAST_6M_UNIQ_Vehicle_Count LAST_6M_Vehicle_Count
1005 01/01/2019 X500 7 6 66
1005 01/02/2019 X500 6 7 62
1005 01/03/2019 X700 7 6 63
1005 01/04/2019 X500 5 7 67
1005 01/05/2019 X700 7 7 66
1005 01/06/2019 X500 7 7 67
. . . .
. . . .
. . . .
1005 03/20/2019 X600 6 12 75
1006 01/01/2019 X500 7 11 74
1006 01/02/2019 X500 6 10 66
1006 01/03/2019 X700 7 11 72
1006 01/04/2019 X500 5 13 67
1006 01/05/2019 X700 7 12 64
1006 01/06/2019 X500 7 12 63
例如,在第一行中,LAST_6M_UNIQ_Vehicle_Count的值为6,因为对于员工ID 1005,(((01/01/2019)-6 month)和01/01/2019之间的车辆ID的唯一计数为其中有6种不同的车辆ID。
我尝试了Over and Partition by,但是缺少6个月的间隔
SELECT t.*,COUNT(DISTINCT t.VEHICLE_ID) OVER (PARTITION BY t.EMP_ID ORDER BY t.DATE)
AS LAST_6M_UNIQ_Vehicle_Count
FROM TABLE1 t
我无法基于每6个月的间隔来计算值。
非常感谢您的帮助。
解决方法
您可以使用窗口功能和范围框架规范来完成此操作。
计算非重复计数有点棘手:Oracle不直接支持它,但是我们可以分两步进行。首先在员工/车辆分区中执行一次窗口计数,然后仅考虑每辆车在员工分区中的首次出现。
所以:
echo
,
在带范围的窗口分析函数中使用Oracle时,Oracle不喜欢COUNT( DISTINCT ... ) OVER ( ... )
,并且会引发ORA-30487: ORDER BY not allowed here
异常(否则,将是解决方案)。如果没有DISTINCT
关键字,它将无法使用。
相反,您可以使用相关子查询:
SELECT t.*,( SELECT COUNT( DISTINCT vehicle_id )
FROM table_name c
WHERE c.emp_id = t.emp_id
AND c."DATE" <= t."DATE"
AND ADD_MONTHS( t."DATE",-6 ) <= c."DATE"
) AS last_6m_uniq_vehicle_count,COUNT(t.vehicle_id) OVER (
PARTITION BY t.emp_id
ORDER BY t."DATE"
RANGE BETWEEN INTERVAL '6' MONTH PRECEDING
AND CURRENT ROW
) AS last_6m_vehicle_count
FROM table_name t
其中的示例数据:
CREATE TABLE table_name ( vehicle_id,emp_id,"DATE" ) AS
SELECT 1,1,DATE '2020-08-31' FROM DUAL UNION ALL
SELECT 2,DATE '2020-07-31' FROM DUAL UNION ALL
SELECT 1,DATE '2020-06-30' FROM DUAL UNION ALL
SELECT 2,DATE '2020-05-31' FROM DUAL UNION ALL
SELECT 2,DATE '2020-04-30' FROM DUAL UNION ALL
SELECT 2,DATE '2020-03-31' FROM DUAL UNION ALL
SELECT 2,DATE '2020-02-29' FROM DUAL UNION ALL
SELECT 2,DATE '2020-01-31' FROM DUAL UNION ALL
SELECT 3,DATE '2020-01-31' FROM DUAL;
输出:
VEHICLE_ID | EMP_ID | DATE | LAST_6M_UNIQ_VEHICLE_COUNT | LAST_6M_VEHICLE_COUNT ---------: | -----: | :-------- | -------------------------: | --------------------: 2 | 1 | 31-JAN-20 | 2 | 2 3 | 1 | 31-JAN-20 | 2 | 2 2 | 1 | 29-FEB-20 | 2 | 3 2 | 1 | 31-MAR-20 | 2 | 4 2 | 1 | 30-APR-20 | 2 | 5 2 | 1 | 31-MAY-20 | 2 | 6 1 | 1 | 30-JUN-20 | 3 | 7 2 | 1 | 31-JUL-20 | 3 | 8 1 | 1 | 31-AUG-20 | 2 | 7
db 提琴here
, MTO指出,count(distinct)
不能用作解决此问题的窗口函数。
因此,我会进行横向连接:
select t.*,l.*
from t cross join lateral
(select count(*) as last_6m_vehicle_count,count(distinct t.vehicle_id) as last_6m_uniq_vehicle_count
from t t2
where t2.emp_id = t.emp_id and
t2.dte <= t.dte and
t2.dte > add_months(t.dte,-6)
) l;
Here是db 小提琴。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。