Reputation: 55
I have a dataset that contains the following columns and data:
Customer | Week_number | Amount
cust1 | 0 | 100
cust1 | 1 | 200
cust1 | 3 | 300
cust2 | 0 | 1000
cust2 | 1 | 2000
I need to calculate fortnightly totals for each customer.
With the window functions, I am able to do this:
SELECT
CUSTOMER, WEEK_NUMBER
, SUM(AMOUNT) OVER (PARTITION BY CUSTOMER ORDER BY WEEK_NUMBER ROWS 1 PRECEDING) AS FORTNIGHT_AMOUNT
FROM AMOUNT
But this adds up the amount even if there is no amount for the previous week. In the example above, for cust1, 3rd row, it adds up week 3 and week 1. The amount should only be added if the week_number is 1 less than the current row's week. Is this possible? Thanks for the help.
What I am getting:
Customer | Week_number | Fortnight_Amount
cust1 | 0 | 100
cust1 | 1 | 300
cust1 | 3 | **500**
cust2 | 0 | 1000
cust2 | 1 | 3000
Expected Result:
Customer | Week_number | Fortnight_Amount
cust1 | 0 | 100
cust1 | 1 | 300
cust1 | 3 | **300**
cust2 | 0 | 1000
cust2 | 1 | 3000
Upvotes: 2
Views: 1712
Reputation: 60482
If it's only two weeks/rows your query can be further simplified to a single STATS-step in Explain (as both OLAP-functions apply the same PARTITION/ORDER) :
SELECT T.*
, CASE
WHEN MAX(WEEK_NUMBER) OVER (PARTITION BY CUSTOMER ORDER BY WEEK_NUMBER ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) + 1 = WEEK_NUMBER
THEN SUM(AMOUNT) OVER (PARTITION BY CUSTOMER ORDER BY WEEK_NUMBER ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
ELSE AMOUNT
END AS TWO_WEEK_SUM_AMOUNT
FROM MY_TABLE T
ORDER BY CUSTOMER, WEEK_NUMBER
Of course this assumes that weeks start with 0 and there's no previous year week 52/53.
Upvotes: 1
Reputation: 55
Thanks @Gordon and @GMB for both your answers. Unfortunately, I am not able to use both the LAG function or the RANGE partitioning in Teradata SQL. But I was able to use the concepts that you both described to get to the below answer.
SELECT
CUSTOMER
, WEEK_NUMBER
, LAG_WEEK_NUMBER
, AMOUNT
, CASE
WHEN WEEK_NUMBER = LAG_WEEK_NUMBER + 1
THEN SUM(AMOUNT) OVER (PARTITION BY CUSTOMER ORDER BY WEEK_NUMBER ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
ELSE AMOUNT
END AS TWO_WEEK_SUM_AMOUNT
FROM (
SELECT
T.*
, MAX(WEEK_NUMBER) OVER (PARTITION BY CUSTOMER ORDER BY WEEK_NUMBER ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS LAG_WEEK_NUMBER
FROM MY_TABLE T
) T
ORDER BY CUSTOMER, WEEK_NUMBER
I was able to get the LAG function implementation in Teradata from @dnoeth's answer in these links:
MAX(WEEK_NUMBER) OVER (PARTITION BY CUSTOMER ORDER BY WEEK_NUMBER ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS LAG_WEEK_NUMBER
rows between 1 preceding and preceding 1
Teradata partitioned query ... following rows dynamically
Please let me know if you find any issues with the answer or if it can be improved in any way.
Upvotes: 0
Reputation: 1270763
You want range
partitioning, not row
partitioning:
SELECT CUSTOMER, WEEK_NUMBER,
SUM(AMOUNT) OVER (PARTITION BY CUSTOMER
ORDER BY WEEK_NUMBER
RANGE BETWEEN 1 PRECEDING AND CURRENT ROW
) AS FORTNIGHT_AMOUNT
FROM AMOUNT;
Upvotes: 0
Reputation: 222632
If you just want to ignore week numbers that are not immediatly sequential, you could use lag()
first, and then do a window sum()
:
select
customer,
week_number,
sum(
case when lag_week_number is null or week_number = lag_week_number + 1
then amount
else 0
end
) over(partition by customer order by week_number) fortnight_amount
from (
select
t.*,
lag(week_number) over(partition by customer order by week_number) lag_week_number
from mytable t
) t
Actually you might actually want to reset the sum
when a there is a gap in week_numbers. For this, which is some kind of gaps-and-islands assignment, you would proceed differently: the idea is to do a cumulative sum
to start a new group when two consecutive week numbers ae note sequential, and then sum within each group:
select
customer,
week_number,
sum(amount) over(partition by customer, grp order by week_date) fortnight_amount
from (
select
t.*,
sum(
case
when lag_week_number is null or week_number = lag_week_number + 1
then 0
else 1
end
) grp
from (
select
t.*,
lag(week_number) over(partition by customer order by week_number) lag_week_number
from mytable t
) t
) t
Upvotes: 0