Good day to everyone!
I have a table with some teams and their rating for the period. Data looks like this:
team | date | rating |
---|---|---|
team_1 | 2022-09 | 7.5 |
team_1 | 2022-12 | 8 |
team_1 | 2023-03 | 8.5 |
team_2 | 2022-09 | 8 |
team_2 | 2022-12 | 7 |
team_2 | 2023-03 | 8 |
team_3 | 2022-09 | 8 |
team_3 | 2022-12 | 8 |
team_3 | 2023-03 | 7 |
team_4 | 2022-09 | 9 |
team_4 | 2022-12 | 8 |
team_4 | 2023-03 | 7 |
As we can see, rating of the team may increase or decrease comparing to the last period, or it can change for two consecutive periods. Thus, team may be classified to one of following groups:
- Increasing for two consecutive periods
- Increased compared to the last period
- Decreased compared to the last period
- Decreasing for two consecutive periods
In this sample, the result should be like this:
team | status |
---|---|
team_1 | Increasing for two consecutive periods |
team_2 | Increased compared to the last period |
team_3 | Decreased compared to the last period |
team_4 | Decreasing for two consecutive periods |
My question is how can I get such result? I suspect there should be some window function, but I’m not sure how exactly to use it.
2
Answers
Yes, window functions, like here:
dbfiddle demo
Compare ratings for each row using lag(), assign sign to get values -1, 0 or 1. Then count these consecutive values for each team and take last row, found with row_number(). Use
case ... when
to present values as you wanted.Edit:
In the above query I assumed, that there can be maximum three enntries for each team, because these were possible team statuses. In case there are more entries gap-n-islands problem need to be solved at first, so query has to be modified like:
so it counts only last consecutive series.
dbfiddle demo
I ended answering a slightly more general case by not limiting comparisons to 3 periods.
It creates a difficult situation where having a rating e.g. increase, then pause (or decrease), then increase again requires us to ignore the first increase and only keep the last.
I let you combine the last 2 columns into a
status
column.Explanation:
1 * 1
and the-1 * -1
, both being> 0
.This product simplifies the
JOIN
criteria quite a bit.LastChange
, which will find the date of the last increase and of the last decrease and, out of both, will keep the earlier date.Note that if the rating of a team only keeps increasing, then the date returned by
COALESCE(MAX(Date) FILTER (WHERE Sign <= 0)
will beNULL
(and symmetrically if it keeps decreasing). In order for theLEAST()
to work well, we need aCOALESCE
.Because your column
date
is in fact a text (the day is missing), I used''
. If it was an actual date, you would need to use-infinity
.You can try what difference it makes with the below sample, in which I added 1 value for
team_3
: