Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
272 views
in Technique[技术] by (71.8m points)

sql - How to get Previous Value for Null Values

I have the Below Data in my Table.

   | Id  |  FeeModeId   |Name        |   Amount|
   ---------------------------------------------
   | 1   |  NULL        | NULL       |   20    |
   | 2   |  1           | Quarter-1  |   5000  |
   | 3   |  NULL        | NULL       |   2000  |    
   | 4   |  2           | Quarter-2  |   8000  |
   | 5   |  NULL        | NULL       |   5000  |
   | 6   |  NULL        | NULL       |   2000  |
   | 7   |  3           | Quarter-3  |   6000  |
   | 8   |  NULL        | NULL       |   4000  |

How to write such query to get below output...

   | Id  |  FeeModeId   |Name        |   Amount|
   ---------------------------------------------
   | 1   |  NULL        | NULL       |   20    |
   | 2   |  1           | Quarter-1  |   5000  |
   | 3   |  1           | Quarter-1  |   2000  |    
   | 4   |  2           | Quarter-2  |   8000  |
   | 5   |  2           | Quarter-2  |   5000  |
   | 6   |  2           | Quarter-2  |   2000  |
   | 7   |  3           | Quarter-3  |   6000  |
   | 8   |  3           | Quarter-3  |   4000  |
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Since you are on SQL Server 2012... here is a version that uses that. It might be faster than other solutions but you have to test that on your data.

sum() over() will do a running sum ordered by Id adding 1 when there are a value in the column and keeping the current value for null values. The calculated running sum is then used to partition the result in first_value() over(). The first value ordered by Id for each "group" of rows generated by the running sum has the value you want.

select T.Id,
       first_value(T.FeeModeId) 
          over(partition by T.NF 
               order by T.Id 
               rows between unbounded preceding and current row) as FeeModeId,
       first_value(T.Name)      
          over(partition by T.NS 
               order by T.Id 
               rows between unbounded preceding and current row) as Name,
       T.Amount
from (
     select Id,
            FeeModeId,
            Name,
            Amount,
            sum(case when FeeModeId is null then 0 else 1 end) 
              over(order by Id) as NF,
            sum(case when Name is null then 0 else 1 end) 
              over(order by Id) as NS
     from YourTable
     ) as T

SQL Fiddle

Something that will work pre SQL Server 2012:

select T1.Id,
       T3.FeeModeId,
       T2.Name,
       T1.Amount
from YourTable as T1
  outer apply (select top(1) Name
               from YourTable as T2
               where T1.Id >= T2.Id and
                     T2.Name is not null
               order by T2.Id desc) as T2
  outer apply (select top(1) FeeModeId
               from YourTable as T3
               where T1.Id >= T3.Id and
                     T3.FeeModeId is not null
               order by T3.Id desc) as T3

SQL Fiddle


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...