SQL Как получить первую строку при изменении значения? - PullRequest
3 голосов
/ 10 марта 2020

У меня есть таблица с идентификаторами, датами и флагом. Я хотел бы получить первую запись в течение определенного года, где флаг явно изменился с 0 на 1.

ID    DATE        FLAG
1    2019-01-31     0
1    2019-02-28     1
1    2019-03-31     1

2    2019-01-31     1
2    2019-02-28     1
2    2019-03-31     1
2    2019-04-30     0
2    2019-05-31     1

3    2019-01-31     0
3    2019-02-28     1
3    2019-03-31     0
3    2019-04-30     1

Так что мой ожидаемый результат будет для 1 , это будет 2019-01-31, 2 будет исключено, а 3 будет 2019-02-28.

Пока у меня есть этот запрос, который работает для большинства часть, но когда я делаю QA, кажется, что запрос не исключает тех, кто начинает с 1, переключается на 0, а затем обратно на 1.

Запрос

SELECT t.ID,
    Date, 
    Flag
 FROM table t
WHERE Flag = '1' 
  AND t.Date > (SELECT MAX(t2.Date) FROM table t2 WHERE t2.ID = t.ID AND t2.Flag = '0' AND t2.Date BETWEEN '2019-01-01' AND '2019-12-31') 
AND t.Date BETWEEN '2019-01-01' AND '2019-12-31'
ORDER BY ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Date);

Любая помощь будет отличной, спасибо!

РЕДАКТИРОВАТЬ: я добавил SQLFiddle

Ответы [ 2 ]

3 голосов
/ 10 марта 2020

Используйте lag() для получения предыдущего флага и затем агрегируйте:

select id, min(date)
from (select *,
             lag(flag) over (partition by id, year(date) order by date) as prev_flag
      from temp
     ) t
where flag = 1 and prev_flag = 0
group by id, year(date);

SQL Fiddle

Возвращает результаты для каждого года. Вы можете, конечно, фильтровать по году в подзапросе, если хотите.

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

Я понимаю, что вам нужен первый 1 - для серий, начинающихся только с 0.

Если вы используете MySQL 8.0, вы можете использовать для этого оконные функции:

select id, min_date
from (
    select 
        id,
        flag,
        row_number() over(partition by id order by date) rn,
        min(case when flag = 1 then date end) over(partition by id) min_date
    from mytable
) t
where rn = 1 and flag = 0

Подзапрос ранжирует записи, имеющие одинаковый id по date, и вычисляет дату первого 1 флага в группе; th ie внешние запросы фильтруют первую запись для каждой группы, гарантируют, что она имеет флаг 0, и отображают вычисленную дату.

...