我想生成两个日期之间的每个月结束日期,但是我需要针对多个组进行操作。简化的示例在这里:
select last_day(add_months(date '2015-01-01', level - 1)), 1 gr from dual
connect by level <= 12
union all
select last_day(add_months(date '2015-01-01', level - 1)), 2 gr from dual
connect by level <= 12;
由于我有很多组,因此可以在没有union all
的情况下在单个SQL查询中完成。
我知道我可以使用PL/SQL
来做到这一点,但是出于好奇,可以使用单个SQL语句吗?
我想要这样的查询:
with d as (
select date '2015-01-01' start_date, date '2015-12-01' end_date, 1 gr from dual
union all
select date '2015-01-01' start_date, date '2015-12-01' end_date, 2 gr from dual
)
select last_day(add_months(start_date, level - 1)) from d
start with start_date = date '2015-01-01'
connect by level <= months_between(end_date, start_date);
但是作为第一个查询生成结果不会cross join
答案 0 :(得分:3)
您可以使用PRIOR
和SYS_GUID()
选项
WITH d
AS (SELECT DATE '2015-01-01' start_date,
DATE '2015-12-01' end_date,
1 gr
FROM dual
UNION ALL
SELECT DATE '2015-01-01' start_date,
DATE '2015-12-01' end_date,
2 gr
FROM dual)
SELECT gr,
last_day(add_months(start_date, LEVEL - 1)) AS dt
FROM d
START WITH start_date = DATE '2015-01-01'
CONNECT BY LEVEL <= months_between(end_date, start_date)
AND PRIOR gr = gr
AND PRIOR sys_guid() IS NOT NULL
ORDER BY gr,
dt
| GR | DT |
|----|----------------------|
| 1 | 2015-01-31T00:00:00Z |
| 1 | 2015-02-28T00:00:00Z |
| 1 | 2015-03-31T00:00:00Z |
| 1 | 2015-04-30T00:00:00Z |
| 1 | 2015-05-31T00:00:00Z |
| 1 | 2015-06-30T00:00:00Z |
| 1 | 2015-07-31T00:00:00Z |
| 1 | 2015-08-31T00:00:00Z |
| 1 | 2015-09-30T00:00:00Z |
| 1 | 2015-10-31T00:00:00Z |
| 1 | 2015-11-30T00:00:00Z |
| 2 | 2015-01-31T00:00:00Z |
| 2 | 2015-02-28T00:00:00Z |
| 2 | 2015-03-31T00:00:00Z |
| 2 | 2015-04-30T00:00:00Z |
| 2 | 2015-05-31T00:00:00Z |
| 2 | 2015-06-30T00:00:00Z |
| 2 | 2015-07-31T00:00:00Z |
| 2 | 2015-08-31T00:00:00Z |
| 2 | 2015-09-30T00:00:00Z |
| 2 | 2015-10-31T00:00:00Z |
| 2 | 2015-11-30T00:00:00Z |
答案 1 :(得分:1)
我找到了另一种方法,但是lateral
也不是我想要的。考施克的答案就是我想要的。
with data as (
select date '2015-01-01' start_date, date '2015-12-01' end_date, 1 as gr from dual
union all
select date '2015-01-01' start_date, date '2015-12-01' end_date, 2 as gr from dual
),
data_level as(
select start_Date
,end_date
,gr
,months_between(end_date,start_date) + 1 as lvl
from data)
select g from data_level,
lateral(select last_day(add_months(start_date,level - 1)) g
from dual
connect by level <= lvl
);