展开行:生成行直到下一次更改

时间:2017-11-06 21:32:49

标签: sql hana

我需要帮助来为下面的问题提出SQL ..我需要每月生成一行,直到我看到下一个更改

对于Ex

ID Price MMYYYY
1  $20  012016
1  $25  082016
1  $30  052017
2  $21  052016
2  $26  112016

结果数据应该是这样的

ID Price MMYYYY
1  $20  012016
1  $20  022016
1  $20  032016
1  $20  042016
1  $20  052016
1  $20  062016
1  $20  072016
1  $25  082016
1  $25  092016
1  $25  102016
1  $25  112016
1  $25  122016
1  $25  012017
1  $25  022017
1  $25  032017
1  $25  042017
1  $30  052017
2  $21  052016
2  $21  062016
2  $21  072016
2  $21  082016
2  $21  092016
2  $21  102016
2  $26  112016

基本上我有重复记录,直到我看到下一个更改..

提前致谢

3 个答案:

答案 0 :(得分:0)

几乎可以在任何SQL数据库中使用:

一种简单的方法是使用您需要的X个月的CROSS JOIN。然后LFT将您的数据(或查询)加入该列表。 e.g。

select concat(m,y) as MMYYYY
from (
    select 2016 as y union all
    select 2017
      ) Years 
cross join (
    select '01' as m union all
    select '02' as m union all
    select '03' as m union all
    select '04' as m union all
    select '05' as m union all
    select '06' as m union all
    select '07' as m union all
    select '08' as m union all
    select '09' as m union all
    select '10' as m union all
    select '11' as m union all
    select '12' as m
      ) Months
LEFT JOIN (
    your-data-here
    ) d ON concat(m,y) = d.mmyyyy

只需根据需要添加/删除多年。

如果您的Hana版本支持CTE,您可以使用它"颠倒"像这样:

with Years as (
    select 2016 as y union all
    select 2017
    )
, Months as (
    select '01' as m union all
    select '02' as m union all
    select '03' as m union all
    select '04' as m union all
    select '05' as m union all
    select '06' as m union all
    select '07' as m union all
    select '08' as m union all
    select '09' as m union all
    select '10' as m union all
    select '11' as m union all
    select '12' as m
    )
select concat(m,y) as MMYYYY
from Years 
cross join Months
LEFT JOIN (
    your-data-here
    ) d ON concat(m,y) = d.mmyyyy

或者您可以使用"递归cte" (常用的表格表达式),但我认为这样做太过分了。

答案 1 :(得分:0)

以下是Used_By_Already查询的一些插件

with cte as
(
select
    data.ID,
    data.rn,
    p.Price,
    data.mmyyyy,
    ifnull(p.Price,0) price2,
    case when p.Price is null then 0 else 1 end as pno

from (
----------
select
    *
from (

select
    row_number() over (order by yyyy, mm) rn,
    yyyy,
    mm,
    concat(mm,yyyy) mmyyyy
from (
    select 2016 as yyyy from dummy
    union all
    select 2017 from dummy
      ) Years 
cross join (
    select '01' as mm from dummy union all
    select '02' as mm from dummy union all
    select '03' as mm from dummy union all
    select '04' as mm from dummy union all
    select '05' as mm from dummy union all
    select '06' as mm from dummy union all
    select '07' as mm from dummy union all
    select '08' as mm from dummy union all
    select '09' as mm from dummy union all
    select '10' as mm from dummy union all
    select '11' as mm from dummy union all
    select '12' as mm from dummy 
      ) Months

) as d
cross join (
    select distinct ID from Prices
) as products
order by ID, rn
----------

) as data
left join Prices as p
    on data.ID = p.ID and
       data.mmyyyy = p.mmyyyy
order by data.ID, rn
)
select
    ID,
    rn,
    mmyyyy,
    max(Price) over (partition by ID, partitionno) as Price
from (
    select
        ID, rn, mmyyyy, Price,
        ( select sum(c.pno) from cte as c where c.ID = cte.ID and c.rn <= cte.rn ) as partitionno
    from cte
) t

我使用SQL Row_Number() function来排序结果,并使用MAX()聚合函数和上面SQL CTE query中的partition by子句 我在SQL查询中使用了CTE表达式,就像在单个脚本块中多次查询子选择语句和临时表一样

上述SQL查询执行的部分输出如下

enter image description here

我希望它有所帮助

答案 2 :(得分:0)

要在接下来的几个月内复制行,直到下一个有效,请尝试:

WITH
x as (-- extract month and year in numeric format
    select *, cast(substring(MMYYYY,1,2) as INTEGER) m, cast(substring(MMYYYY,3,4) as INTEGER) y
    from YourTable
),
m as (-- prepare numbers 1..12 (list of monts)
    select top 12 ROW_NUMBER() over (order by OBJECT_OID) m
    from sys.OBJECTS
),
y as (-- expand years needed for each id
    select distinct id, m.m, y
    from x, m
)
-- let's do the trick
select x.ID, x.Price, right('0'+cast(y.m as varchar(2)),2)+cast(y.y as varchar(4)) MMYYYY
from y
inner join x on 
    -- same ID
    y.ID = x.ID and (
    -- match all rows from this one..
    (x.y*100+x.m <= y.y*100+y.m) 
    and not exists (
        -- until not exists a following valid row
        select 1 
        from x xx 
        -- same id
        where y.ID = xx.ID
        -- following this one
        and (xx.y*100+xx.m > x.y*100+x.m) 
        -- but preceding the current row
        and (xx.y*100+xx.m <= y.y*100+y.m))
    )
order by y.id, y.y, y.m

输出

ID  Price   MMYYYY
1   $20     012016
1   $20     022016
1   $20     032016
1   $20     042016
1   $20     052016
1   $20     062016
1   $20     072016
1   $25     082016
1   $25     092016
1   $25     102016
1   $25     112016
1   $25     122016
1   $25     012017
1   $25     022017
1   $25     032017
1   $25     042017
1   $30     052017
1   $30     062017
1   $30     072017
1   $30     082017
1   $30     092017
1   $30     102017
1   $30     112017
1   $30     122017
2   $21     052016
2   $21     062016
2   $21     072016
2   $21     082016
2   $21     092016
2   $21     102016
2   $26     112016
2   $26     122016