Определить изменения для каждого идентификатора - PullRequest
0 голосов
/ 20 апреля 2020

Предположим, у меня есть следующие данные

ID   | year_month | Department
1233 | 2020-01-01 | A
1123 | 2020-02-01 | A
1123 | 2020-03-01 | NULL
1123 | 2020-04-01 | B
1123 | 2020-05-01 | B
1123 | 2020-06-01 | B
1123 | 2020-07-01 | NULL
9999 | 2020-01-01 | A
9999 | 2020-02-01 | A
9999 | 2020-03-01 | B
9999 | 2020-04-01 | B
9999 | 2020-05-01 | B
9999 | 2020-06-01 | A
9999 | 2020-07-01 | B

Я хочу определить изменения в отделе. , в том числе идущий в NA / NULL. Желаемый результат:

ID   | Change_year_month | Old_Department | New_Department
1123 | 2020-03-01        | A              | NULL
1123 | 2020-04-01        | NULL           | B
1123 | 2020-07-01        | B              | NULL
9999 | 2020-03-01        | A              | B
9999 | 2020-06-01        | B              | A

Идеи, которые я уже пытался реализовать:

with x as(
SELECT T1.ID, T1.Department, MIN(T1.year_month) AS Change_year_month FROM dbo.Source
GROUP BY T1.ID, Department),
y as (
SELECT ID, year_month, 
rown = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY year_month) FROM x
)
select y.ID, T2.Department, year_month AS Change_year_month FROM y
right join (SELECT T1.ID,
MAX(Department) as Old_Department,
Min(Department) AS New_Department
FROM dbo.Source
GROUP BY T1.ID HAVING COUNT(DISTINCT(Department)) >= 2) T2 on y.ID = T2.ID
where rown = 1 

Однако это не дает желаемого результата. Всякий раз, когда задействован NULL, запрос не видит изменения. Всякий раз, когда я изменяю NULL на что-то другое (например, «вне области видимости»), тогда порядок неправильный, так как Old_department никогда не находится «вне области видимости», но всегда New_department. Кроме того, я чувствую, что код неэффективен и не долговечен.

У кого-нибудь есть предложения, как поступить или построить длительный запрос?

1 Ответ

1 голос
/ 20 апреля 2020

Вот довольно простой метод, использующий lag():

select s.id, s.year_month, s.prev_department, s.department
from (select s.*,
             lag(year_month) over (partition id order by year_month) as prev_ym,
             lag(year_month) over (partition id, department order by year_month) as prev_ym_dept,
             lag(department) over (partition by id order by year_month) as prev_department
      from dbo.source s
     ) s
where prev_ym_dept <> prev_ym;

. Здесь рассматриваются даты для сравнения, поэтому он просто обрабатывает NULL значений.

Конечно, Вы можете использовать более сложные сравнения:

select s.id, s.year_month, s.prev_department, s.department
from (select s.*,
             lag(year_month) over (partition id order by year_month) as prev_ym,
             min(year_month) over (partition by id) as min_year_month
      from dbo.source s
     ) s
where prev_department <> department or
      (department is null and
       prev_department is not null
      ) or
      (prev_department is null and
       department is not null and
       year_month <> min_year_month
      )

Но это довольно сложно для express. И это может даже привести к ошибке при фильтрации первого ряда.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...