I have a SQL table of date entries with three columns: date, item, and status. The table appears like this:
date | item | status |
---|---|---|
2023-01-01 | A | on |
2023-01-01 | B | on |
2023-01-01 | C | off |
2023-01-02 | A | on |
2023-01-02 | B | off |
2023-01-02 | C | off |
2023-01-02 | D | on |
2023-01-03 | A | on |
2023-01-03 | B | off |
2023-01-03 | C | off |
2023-01-03 | D | off |
Looking at the most recent entries, I need grouped by item, the latest date and status, and a count on the running total of entries where status has not changed. For example, the output I am looking for would be:
latest_date | item | current_status | number_of_days_on_current |
---|---|---|---|
2023-01-03 | A | on | 3 |
2023-01-03 | B | off | 2 |
2023-01-03 | C | off | 3 |
2023-01-03 | D | off | 1 |
How would I get the output I want in PostgreSQL 13.7?
This returns the latest date, item, and current status, but does not correctly count the number of days the item has been on the current status:
WITH CTE AS (
SELECT
item,
date,
status,
LAG(status) OVER (PARTITION BY item ORDER BY date) AS prev_status,
ROW_NUMBER() OVER (PARTITION BY item ORDER BY date DESC) AS rn
FROM
schema.table
)
SELECT
MAX(date) AS latest_date,
item,
status AS current_status,
SUM(CASE WHEN prev_status = status THEN 0 ELSE 1 END)
OVER (PARTITION BY item ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS number_of_days
FROM
CTE
WHERE
rn = 1
GROUP BY
item, status, prev_status, date
ORDER BY
item
2
Answers
Using a
cte
to build the runs of consecutive statuses:See fiddle.
According to your comment, you want to find the max count of consecutive statuses
where status = last status value
, this became a gaps and islands problem. This can be solved using a difference between two row_numbers and thelast_value
function as the following:See demo