#sql #sql-server
#sql #sql-сервер
Вопрос:
У меня есть таблица, подобная приведенной ниже. Записи не имеют первичного ключа, и я хочу добиться этого как С ПОМОЩЬЮ, так и БЕЗ функции ЗАДЕРЖКИ и ОПЕРЕЖЕНИЯ.
ID ENTID INOUTDATE YEAR MONTH STATUS
1923 1923 [NULL] 2099 12 Out
1923 10690 [NULL] 2099 12 Out
1923 9670 2012-08-24 00:00:00 2012 8 In
1923 1923 2013-06-01 00:00:00 2013 6 In
1923 9670 2018-04-19 00:00:00 2018 4 Out
1923 10690 2019-02-01 00:00:00 2019 2 In
И я хочу получить записи, как указано ниже.
ID ENTID INOUTDATE YEAR MONTH STATUS
1923 10690 [NULL] 2099 12 Out
1923 9670 2012-08-24 00:00:00 2012 8 In
1923 9670 2018-04-19 00:00:00 2018 4 Out
1923 10690 2019-02-01 00:00:00 2019 2 In
Комментарии:
1. Почему вы хотите избежать
lad()
/lead()
? Какова логика фильтрации, которую вы хотите выполнить?2. Привет, Гордон, я отредактировал свой вопрос. Если возможно, можете ли вы показать оба способа. Спасибо.
3. @GordonLinoff Вероятно, чтобы они могли поддерживать версии старше, чем когда
LAG()
/LEAD()
были введены.
Ответ №1:
lag()
это самый простой метод:
select t.*
from (select t.*,
lag(status) over (partition by id, (case when inoutdate is null then 1 else 2 end)
order by inoutdate
) as prev_status
from t
) t
where prev_status is null or prev_status <> status;
Вы можете рассматривать это как проблему группы и островов, идентифицируя острова с помощью row_number()
. Логика более сложная:
select t.*
from (select t.*,
row_number() over (partition by id, (case when inoutdate is null then 1 else 2 end), status, (seqnum - seqnum_s)
order by inoutdate
) as seqnum_g
from (select t.*,
row_number() over (partition by id, (case when inoutdate is null then 1 else 2 end) order by inoutdate) as seqnum,
row_number() over (partition by id, (case when inoutdate is null then 1 else 2 end), status order by inoutdate) as seqnum_s
from t
) t
) t
where seqnum_g = 1;