oracle SQL 确定月中的连续周期
oracle SQL determine consecutive periods in months
早上好,
我每隔 1 个月就为我的数据仓库收集数据。
现在我想用 oracle sql.
确定几个月的连续周期是多少
如果这个月有中断,我想开始新的一期。
我的示例与下面的示例类似:
ID LOAD_DATE
100 20190101
100 20190201
100 20190401
100 20190501
100 20190601
100 20190701
100 20191001
100 20191101
100 20191201
100 20200101
200 20190701
200 20190901
200 20191101
200 20191201
200 20200101
200 20200201
期望的结果:
ID From To
100 20190101 20190201
100 20190401 20190701
100 20191001 20200101
200 20190701 20190701
200 20190901 20190901
200 20191101 20200201
我可以管理基于一年的连续周期。由于年份的变化,我无法按月进行。
请帮忙。
我正在使用 Oracle sql 开发人员
实际支持的版本(即Oracle 12+):
select *
from t
match_recognize(
partition by id
order by load_date
measures
first(LOAD_DATE) as ld,
LAST(LOAD_DATE) AS lst,
count(*) as cnt
pattern (strt next*)
define
next as next.load_date=add_months(prev(load_date),1)
)
order by 1,2;
带有示例数据的完整示例:
alter session set nls_date_format='yyyymmdd';
with t (ID,LOAD_DATE) as (
select 100, to_date('20190101') from dual union all
select 100, to_date('20190201') from dual union all
select 100, to_date('20190401') from dual union all
select 100, to_date('20190501') from dual union all
select 100, to_date('20190601') from dual union all
select 100, to_date('20190701') from dual union all
select 100, to_date('20191001') from dual union all
select 100, to_date('20191101') from dual union all
select 100, to_date('20191201') from dual union all
select 100, to_date('20200101') from dual union all
select 200, to_date('20190701') from dual union all
select 200, to_date('20190901') from dual union all
select 200, to_date('20191101') from dual union all
select 200, to_date('20191201') from dual union all
select 200, to_date('20200101') from dual union all
select 200, to_date('20200201') from dual
)
select *
from t
match_recognize(
partition by id
order by load_date
measures
first(LOAD_DATE) as ld,
LAST(LOAD_DATE) AS lst,
count(*) as cnt
pattern (strt next*)
define
next as next.load_date=add_months(prev(load_date),1)
)
order by 1,2;
我了解了一部分,正在处理剩余部分。
SELECT X.ID, X.LOAD_DATE, X.NEXT_MONTH FROM (
SELECT CASE
WHEN TRUNC(ADD_MONTHS(TO_DATE(LOAD_DATE, 'YYYY-MM-DD'), 1)) = TRUNC(TO_DATE(NEXT_MONTH, 'YYYY-MM-DD'))
THEN 1 ELSE 0 END AS CHECK_VALUE, A.* FROM
(
SELECT A.*, LEAD(LOAD_DATE) OVER(PARTITION BY ID ORDER BY LOAD_DATE) NEXT_MONTH
FROM TABLE1 A ) A) X WHERE CHECK_VALUE = 1;
一种解决方案使用 window 函数,将实际日期存储为数字,如下所示:
select id, min(load_date) "To", max(load_date) "From"
from (
select id, load_date,
sum(period_start) over (partition by id order by load_date_converted)
period
from (
select id, load_date,
to_date(load_date,'YYYYMMDD') load_date_converted,
case when add_months(to_date(load_date,'YYYYMMDD'),-1)<>
lag (to_date(load_date,'YYYYMMDD'),1,sysdate)
over (partition by id order by load_date)
then 1 else 0
end period_start
from table_name
)
)
group by id, period
order by id, period
甲骨文版本:12c
最简单的方法是做一个简单的观察:如果您有一个数字序列来枚举每一行,那么当月份连续时,这个序列和加载日期之间的差异(以月为单位)是恒定的。然后,您可以按此差异进行汇总:
select id, min(load_date), max(load_date)
from (select t1.*, row_number() over (partition by id order by load_date) as seqnum
from table1 t1
) t1
group by id, add_months(to_date(load_date, 'YYYYMMDD'), - seqnum)
order by id, min(load_date);
Here 是一个 db<>fiddle.
早上好,
我每隔 1 个月就为我的数据仓库收集数据。 现在我想用 oracle sql.
确定几个月的连续周期是多少如果这个月有中断,我想开始新的一期。
我的示例与下面的示例类似:
ID LOAD_DATE
100 20190101
100 20190201
100 20190401
100 20190501
100 20190601
100 20190701
100 20191001
100 20191101
100 20191201
100 20200101
200 20190701
200 20190901
200 20191101
200 20191201
200 20200101
200 20200201
期望的结果:
ID From To
100 20190101 20190201
100 20190401 20190701
100 20191001 20200101
200 20190701 20190701
200 20190901 20190901
200 20191101 20200201
我可以管理基于一年的连续周期。由于年份的变化,我无法按月进行。
请帮忙。 我正在使用 Oracle sql 开发人员
实际支持的版本(即Oracle 12+):
select *
from t
match_recognize(
partition by id
order by load_date
measures
first(LOAD_DATE) as ld,
LAST(LOAD_DATE) AS lst,
count(*) as cnt
pattern (strt next*)
define
next as next.load_date=add_months(prev(load_date),1)
)
order by 1,2;
带有示例数据的完整示例:
alter session set nls_date_format='yyyymmdd';
with t (ID,LOAD_DATE) as (
select 100, to_date('20190101') from dual union all
select 100, to_date('20190201') from dual union all
select 100, to_date('20190401') from dual union all
select 100, to_date('20190501') from dual union all
select 100, to_date('20190601') from dual union all
select 100, to_date('20190701') from dual union all
select 100, to_date('20191001') from dual union all
select 100, to_date('20191101') from dual union all
select 100, to_date('20191201') from dual union all
select 100, to_date('20200101') from dual union all
select 200, to_date('20190701') from dual union all
select 200, to_date('20190901') from dual union all
select 200, to_date('20191101') from dual union all
select 200, to_date('20191201') from dual union all
select 200, to_date('20200101') from dual union all
select 200, to_date('20200201') from dual
)
select *
from t
match_recognize(
partition by id
order by load_date
measures
first(LOAD_DATE) as ld,
LAST(LOAD_DATE) AS lst,
count(*) as cnt
pattern (strt next*)
define
next as next.load_date=add_months(prev(load_date),1)
)
order by 1,2;
我了解了一部分,正在处理剩余部分。
SELECT X.ID, X.LOAD_DATE, X.NEXT_MONTH FROM (
SELECT CASE
WHEN TRUNC(ADD_MONTHS(TO_DATE(LOAD_DATE, 'YYYY-MM-DD'), 1)) = TRUNC(TO_DATE(NEXT_MONTH, 'YYYY-MM-DD'))
THEN 1 ELSE 0 END AS CHECK_VALUE, A.* FROM
(
SELECT A.*, LEAD(LOAD_DATE) OVER(PARTITION BY ID ORDER BY LOAD_DATE) NEXT_MONTH
FROM TABLE1 A ) A) X WHERE CHECK_VALUE = 1;
一种解决方案使用 window 函数,将实际日期存储为数字,如下所示:
select id, min(load_date) "To", max(load_date) "From"
from (
select id, load_date,
sum(period_start) over (partition by id order by load_date_converted)
period
from (
select id, load_date,
to_date(load_date,'YYYYMMDD') load_date_converted,
case when add_months(to_date(load_date,'YYYYMMDD'),-1)<>
lag (to_date(load_date,'YYYYMMDD'),1,sysdate)
over (partition by id order by load_date)
then 1 else 0
end period_start
from table_name
)
)
group by id, period
order by id, period
甲骨文版本:12c
最简单的方法是做一个简单的观察:如果您有一个数字序列来枚举每一行,那么当月份连续时,这个序列和加载日期之间的差异(以月为单位)是恒定的。然后,您可以按此差异进行汇总:
select id, min(load_date), max(load_date)
from (select t1.*, row_number() over (partition by id order by load_date) as seqnum
from table1 t1
) t1
group by id, add_months(to_date(load_date, 'YYYYMMDD'), - seqnum)
order by id, min(load_date);
Here 是一个 db<>fiddle.