Установите все значения в столбце равными первому ненулевому значению в окне в Postgres - PullRequest
1 голос
/ 07 марта 2020

Возьмем эту таблицу в качестве примера:

+----+------------+------+
| id |    date    | flag |
+----+------------+------+
| A  | 01/01/2020 |    0 |
| A  | 01/02/2020 |    0 |
| A  | 01/03/2020 |    0 |
| A  | 01/04/2020 |    1 |
| A  | 01/05/2020 |    1 |
| B  | 01/01/2020 |    0 |
| B  | 01/02/2020 |    1 |
| B  | 01/03/2020 |    1 |
| B  | 01/04/2020 |    1 |
| B  | 01/05/2020 |    1 |
+----+------------+------+

Существует флаг, установленный в 0 или 1. Я хочу создать новый столбец с именем day_flagged, который будет содержать дату, когда Сначала флаг стал 1. Например, для id A это будет 01/04/2020. Для id B это будет 01/02/2020.

Это то, что у меня сейчас есть:

SELECT x.id, 
       x.date, 
       ( CASE 
           WHEN prev_flag = 0 
                AND next_flag = 1 
                AND x.flag = 1 THEN 1 
           ELSE NULL 
         END ) AS flagged 
FROM   (SELECT id, 
               date, 
               flag, 
               Lag(flag) 
                 OVER ( 
                   partition BY id 
                   ORDER BY date ASC) AS prev_flag, 
               Lead(flag) 
                 OVER ( 
                   partition BY id 
                   ORDER BY date ASC) AS next_flag 
        FROM   tableA) AS x;

Результат этого таков:

+----+------------+---------+
| id |    date    | flagged |
+----+------------+---------+
| A  | 01/01/2020 | null    |
| A  | 01/02/2020 | null    |
| A  | 01/03/2020 | null    |
| A  | 01/04/2020 | 1       |
| A  | 01/05/2020 | null    |
| B  | 01/01/2020 | null    |
| B  | 01/02/2020 | 1       |
| B  | 01/03/2020 | null    |
| B  | 01/04/2020 | null    |
| B  | 01/05/2020 | null    |
+----+------------+---------+

Я могу определить, когда значение flag для каждого id впервые изменилось с 0 на 1, и сохранить его в flagged. Как я могу взять значение date, соответствующее строкам, где flagged равно 1, и вставить эту дату в каждую строку раздела как day_flagged?

Желаемый результат:

+----+------------+------+-------------+
| id |    date    | flag | day_flagged |
+----+------------+------+-------------+
| A  | 01/01/2020 |    0 | 01/04/2020  |
| A  | 01/02/2020 |    0 | 01/04/2020  |
| A  | 01/03/2020 |    0 | 01/04/2020  |
| A  | 01/04/2020 |    1 | 01/04/2020  |
| A  | 01/05/2020 |    1 | 01/04/2020  |
| B  | 01/01/2020 |    0 | 01/02/2020  |
| B  | 01/02/2020 |    1 | 01/02/2020  |
| B  | 01/03/2020 |    1 | 01/02/2020  |
| B  | 01/04/2020 |    1 | 01/02/2020  |
| B  | 01/05/2020 |    1 | 01/02/2020  |
+----+------------+------+-------------+

DB Fiddle: https://www.db-fiddle.com/f/wJsTnvNkYELHqLjHRx1pie/4

1 Ответ

1 голос
/ 07 марта 2020

Я понимаю, что вам нужна дата первого 1 для каждого id.

Если это так, похоже, что условное окно min() подойдет вам:

select
    t.*,
    min(date) filter(where flag = 1) over(partition by id) day_flagged
from tableA t

Демонстрация на DB Fiddle :

| id  | date       | flag | day_flagged |
| --- | ---------- | ---- | ----------- |
| A   | 01/01/2020 | 0    | 01/04/2020  |
| A   | 01/02/2020 | 0    | 01/04/2020  |
| A   | 01/03/2020 | 0    | 01/04/2020  |
| A   | 01/04/2020 | 1    | 01/04/2020  |
| A   | 01/05/2020 | 1    | 01/04/2020  |
| B   | 01/01/2020 | 0    | 01/02/2020  |
| B   | 01/02/2020 | 1    | 01/02/2020  |
| B   | 01/03/2020 | 1    | 01/02/2020  |
| B   | 01/04/2020 | 1    | 01/02/2020  |
| B   | 01/05/2020 | 1    | 01/02/2020  |
...