简体   繁体   中英

SQL sum window function with frame clause and where clause

I have a table structured as follows:

month  | ds         | item | qty|
--------------------------
1/1/20 | 2020-02-01 | abc | 0 |    
2/1/20 | 2020-03-01 | abc | 0 |     
3/1/20 | 2020-04-01 | abc | 0 |     
4/1/20 | 2020-05-01 | abc | 0 |     
5/1/20 | 2020-06-01 | abc | 0 |     
6/1/20 | 2020-07-01 | abc | 50 |    
7/1/20 | 2020-08-01 | abc | 50 |    
8/1/20 | 2020-08-09 | abc | 50 |    
9/1/20 | 2020-08-09 | abc | 50 |

The table is partitioned by the ds (datestamp) column. Each partition has months which span from 2019 to 2021.

I need to be able to sum qty over a 90d, 180d, and 365d period but on the following condition: if month is less than today's date then we need to use ds that starts on the first of the next month (ie if we want to calculate for July then we would use aug 1st ds - this is shown in the table). If the month is current month or future then I would need to use the latest ds available.

I have tried using a window function to do the sum but this doesn't work when multiple partitions are involved b/c I need to do the sum using the same partition. For example, 1/1/20 I need to do a sum of Feb, Mar, Apr using 2020-02-01 partition (if you see in the table 2/1/20 to 4/1/20 uses a diff partition for each row). In other words, I would need something like this:

select SUM(qty) OVER (
        PARTITION BY
            item
        ORDER BY
            DATE(month) ROWS BETWEEN 1 FOLLOWING AND 3 FOLLOWING
    ) AS sum_90_qty
 from table A
 where ds = <whatever is in the ds column> 

Once this is done for Jan then I would need it to start on Feb using 2020-03-01 ds summing mar, apr, and may so on and so forth.

Expected Output should look as follows:

month  | ds         | item | qty| 90d_sum
--------------------------
1/1/20 | 2020-02-01 | abc | 0 | 0    
2/1/20 | 2020-03-01 | abc | 0 | 0     
3/1/20 | 2020-04-01 | abc | 0 | 90

This is assuming (2/1/20, 3/1/20, 4/1/20 all are 0 in the 2020-02-01 partition). Same would be the case for 3/1/20, 4/1/20, 5/1/20 in 2020-03-01 partition. Sample for 2020-04-01 partition: 4/1/20 has 0, 5/1/20 has 40, 6/1/20 has 50 --> so the sum from 0+40+50 = 90. Note: The numbers i've included are just random but the idea is that it needs to sum 3 months based on the month value and the ds column.

Thanks!

You want to calculate the appropriate ds for each month. This would be the first one following the month or the most recent month. So for each item / month combination, we can calculate this:

select a.*
from (select a.*,
             row_number() over (partition by item, month
                                order by (ds > month) desc,
                                         (case when ds > month then ds end) asc,
                                         ds desc
                               ) as seqnum
      from a
     ) a
where seqnum = 1;

You can then incorporate this logic into your final query. I think that would just be:

select a.*,
       sum(qty) over (partition by item 
                      order by date(month)
                      rows between 1 following and 3 following
                     ) as running_qty_3month
from (select a.*,
             row_number() over (partition by item, month
                                order by (ds > month) desc,
                                         (case when ds > month then ds end) asc,
                                         ds desc
                               ) as seqnum
      from a
     ) a
where seqnum = 1;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM