2013-10-16 110 views
1

我想基於有序列表生成累積信息。 在下面的例子中,我想根據其他3列生成雨天。 按城鎮和天排序,如果天氣乾燥,則爲空,如果天氣爲雨,則爲累積分數。使用SQL根據有序列表生成累積信息

程序上這很容易,但它感覺應該有一種方式來直接與SQL生成它,我只是無法弄清楚。

可能你可以使用分析範圍窗口,但我無法弄清楚如何跨3列做到這一點。如果存在中間行,需要重置意味着我不能忽略「幹」行並只使用row_number()。

town  day weather days of rain 
Stevenage 1 dry  
Stevenage 2 dry  
Stevenage 3 rain  1 
Stevenage 4 rain  2 
Stevenage 4 rain  3 
Stevenage 5 dry  
Stevenage 6 dry  
Stevenage 8 rain  1 
Stevenage 9 rain  2 
Stevenage 10 dry  
Watford 1 dry  
Watford 2 dry  
Watford 3 rain  1 
Watford 4 rain  2 





create table rain_test (town varchar2(20), day number, weather varchar2(10), days_of_rain number); 

insert into rain_test(town, day, weather) values ('Stevenage', 1, 'dry'); 
insert into rain_test(town, day, weather) values ('Stevenage', 2, 'rain'); 
insert into rain_test(town, day, weather) values ('Stevenage', 3, 'rain'); 
insert into rain_test(town, day, weather) values ('Stevenage', 4, 'rain'); 
insert into rain_test(town, day, weather) values ('Stevenage', 5, 'dry'); 
insert into rain_test(town, day, weather) values ('Stevenage', 6, 'dry'); 
insert into rain_test(town, day, weather) values ('Stevenage', 7, 'rain'); 
insert into rain_test(town, day, weather) values ('Stevenage', 8, 'rain'); 
insert into rain_test(town, day, weather) values ('Stevenage', 9, 'rain'); 
insert into rain_test(town, day, weather) values ('Stevenage', 10, 'dry'); 
insert into rain_test(town, day, weather) values ('Watford', 1, 'dry'); 
insert into rain_test(town, day, weather) values ('Watford', 2, 'dry'); 
insert into rain_test(town, day, weather) values ('Watford', 3, 'rain'); 
insert into rain_test(town, day, weather) values ('Watford', 4, 'rain'); 
commit; 
+0

聽起來一個分析或窗口功能的工作。 –

回答

1

使用分析功能,

with x as (
    select town, 
     day, 
     weather, 
     case when weather =    --lag function to find out when the weather changes. 
        lag(weather,1) over (partition by town order by day) 
       then 0 
       else 1 
     end boundary 
    from rain_test 
), 
y as (
    select town, day, weather, 
     sum(boundary) over (partition by town order by day) grp --Sum function to assign a unique group number to a sequence of same weather. 
    from x 
) 
select town, day, weather, 
     case when weather = 'rain' 
      then row_number() over (partition by town, grp order by day) --row_number function to assign unique number to each row in a group. 
     end 
    from y 
order by town, day; 

Demo at sqlfiddle

+0

非常聰明,謝謝。 – Aunib

0

你去那裏,只是爲了挑戰,肯定要容易得多程序上,但不是很好玩:

select town, day, weather, null days_of_rain 
from rain_test 
where weather = 'dry' 
union 
select day.town, day.day, weather, day.day - chain.begin_day + 1 days_of_rain 
from rain_test day, 
     (
     select town, chain, sum(begin_day) begin_day, sum(end_day) end_day 
     from (/* to find the chains of rainy days */  
       select town, rownum chain, day begin_day, 0 end_day 
       from (/* to find the begining days */ 
        select rain.town, rain.day 
        from rain_test rain, 
          rain_test day 
        where rain.town = day.town 
        and rain.weather = 'rain' 
        and day.day = rain.day - 1 
        and day.weather = 'dry' 
        union /* border condition */ 
        select town, min(day) day 
        from rain_test 
        where weather = 'rain' 
        group by town 
        order by town, day 
        ) 
       union all 
       select town, rownum chain, 0 begin_day, day end_day 
       from (/* to find the ending days */  
        select rain.town, rain.day 
        from rain_test rain, 
          rain_test day 
        where rain.town = day.town 
        and rain.weather = 'rain' 
        and day.day = rain.day + 1 
        and day.weather = 'dry' 
        union /* border condition */ 
        select town, max(day) day 
        from rain_test 
        where weather = 'rain' 
        group by town 
        order by town, day 
        )  
      ) 
     group by town, chain 
     ) chain 
where chain.town = day.town 
and chain.begin_day <= day.day 
and chain.end_day >= day.day   
order by town, day 
+0

非常聰明,謝謝。 – Aunib