多个组的分层查询

时间:2018-08-07 08:42:25

标签: sql oracle

我想生成两个日期之间的每个月结束日期,但是我需要针对多个组进行操作。简化的示例在这里:

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

2 个答案:

答案 0 :(得分:3)

您可以使用PRIORSYS_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 |

Demo

答案 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
);