Пометить записи через 7 дней после ранее идентифицированной записи

Я хочу пометить те строки, которые находятся на расстоянии >= 7 дней от ранее идентифицированной записи. В примере ниже допустимыми строками являются 4-13-2022, 4-20-2022 и 4-28-2022.

drop table #tmp1
create table #tmp1(
membernum int,
sevrfromdate date
)

insert into #tmp1
values (1000016, '4/13/2022')
insert into #tmp1
values (1000016, '4/15/2022')
insert into #tmp1
values (1000016, '4/20/2022')
insert into #tmp1
values (1000016, '4/22/2022')
insert into #tmp1
values (1000016, '4/23/2022')
insert into #tmp1
values (1000016, '4/28/2022')

Это моя неудачная попытка отметить рекорды.

select *,
case when datediff(d,coalesce(lag(sevrfromdate) over (partition by membernum order by sevrfromdate),
                        dateadd(d, -7, sevrfromdate)), sevrfromdate) > = 5 then 1 else 0 end as lasttm,
                        lag(sevrfromdate) over (partition by membernum order by sevrfromdate)
from #tmp1

желаемый результат

В соответствии с руководством по вопросам не публикуйте изображения кода, данных, сообщений об ошибках и т. д. — скопируйте или введите текст в вопрос. Пожалуйста, ограничьте использование изображений для диаграмм или демонстрации ошибок рендеринга, вещей, которые невозможно точно описать с помощью текста.

Dale K 02.08.2024 02:54

Обратите внимание на добавленное мной форматирование кода, которое вы удалили при редактировании.

Dale K 02.08.2024 03:15

Не могли бы вы объяснить, как должна работать ваша логика? (непонятно, что вы подразумеваете под «ранее идентифицировать запись»); ваш предпринятый запрос помечает каждую строку как 1, если ее дата подачи более чем на 4 дня позже даты подачи предыдущей строки (лаг). Я не понимаю, как вы отметили свои строки цифрой 1.

tinazmu 02.08.2024 07:28

Что такое «идентификационная запись»?

Jonas Metzler 02.08.2024 07:35

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

jarlh 02.08.2024 09:10

Обратите внимание, что в таблицах есть строки, а не записи.

jarlh 02.08.2024 09:10

У меня такое ощущение, что вам нужен способ рекурсивно получать строки, находящиеся на расстоянии >= 7 дней от ранее определенной строки, в этом случае LAG нельзя использовать, и вам, вероятно, понадобится CTE.

siggemannen 02.08.2024 09:24

«Идентифицированная запись» будет следующей записью >=7 дней. В приведенном выше примере следующей идентифицированной записью будет 28 апреля 2022 г.

batoni 02.08.2024 16:55
28 - 23 = 5, что составляет менее 7 дней.
Eric 02.08.2024 18:03

Сравнение будет проводиться не с 23 апреля 2022 г., а с ранее определенной строкой для 20 апреля 2022 г. Итак, с 20 апреля 22 года следующая действительная строка — 28 апреля 2022 года.

batoni 02.08.2024 21:59
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
10
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

WITH CTE AS (
    SELECT
        membernum,
        sevrfromdate,
        ROW_NUMBER() OVER (PARTITION BY membernum ORDER BY sevrfromdate) AS rn
    FROM #tmp1
),
FlaggedRecords AS (
    SELECT
        c1.membernum,
        c1.sevrfromdate,
        CASE
            WHEN c1.rn = 1 THEN 'True'
            WHEN DATEDIFF(DAY, c2.sevrfromdate, c1.sevrfromdate) >= 7 THEN 'True'
            ELSE 'False'
        END AS Is7days
    FROM CTE c1
    LEFT JOIN CTE c2
    ON c1.membernum = c2.membernum
    AND c1.rn = c2.rn + 1
),
TrackingCTE AS (
    SELECT
        membernum,
        sevrfromdate,
        Is7days,
        MAX(CASE WHEN Is7days = 'True' THEN sevrfromdate END) 
            OVER (PARTITION BY membernum ORDER BY sevrfromdate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS LastTrueDate
    FROM FlaggedRecords
),
FinalFlagging AS (
    SELECT
        membernum,
        sevrfromdate,
        Is7days,
        LastTrueDate,
        CASE
            WHEN Is7days = 'True' THEN 'True'
            WHEN DATEDIFF(DAY, LastTrueDate, sevrfromdate) >= 7 THEN 'True'
            ELSE 'False'
        END AS FinalIs7days
    FROM TrackingCTE
)
SELECT membernum, sevrfromdate, FinalIs7days, LastTrueDate
FROM FinalFlagging
ORDER BY sevrfromdate;

Этот запрос даст вам желаемый результат. FiddlerOutput

Цитата

Если я изменю набор записей. код не возвращает правильные флаги. INSERT INTO ##tmp1 (membernum, sevrfromdate) ЗНАЧЕНИЯ (1000016, '2022-04-13'), (1000016, '2022-04-15'), (1000016, '2022-04-20'), (1000016, '22.04.2022'), (1000016, '23.04.2022'), (1000016, '30.04.2022');

batoni 02.08.2024 14:33

В этом случае правильные значения: 2022-04-13, 2022-04-20, 2022-04-30.

batoni 02.08.2024 15:05
Ответ принят как подходящий

Как указал выше @siggemannen, здесь мы можем использовать рекурсивный запрос для выбора первой и следующей помеченной даты.

  1. Сначала вычислите возможную следующую дату для каждой строки — min(sevrfromdate), где эта дата>=7 дней от текущей даты строки.
  2. Затем мы берем первую строку (очевидно, помеченную) и рекурсивно берем другие помеченные строки.
  3. Наконец, присоедините исходную таблицу с помощью рекурсивного запроса.

См. пример

номер члена sevrfromdate 1000016 13 апреля 2022 г. 1000016 15 апреля 2022 г. 1000016 20 апреля 2022 г. 1000016 2022-04-22 1000016 2022-04-23 1000016 2022-04-28
with t as(
  select membernum, sevrfromdate
    ,(select min(sevrfromdate)
      from #tmp1 t2 where t2.membernum=t.membernum
       and t2.sevrfromdate>=dateadd(d,7,t.sevrfromdate)
  )  nextdate
  from #tmp1 t

)
,r as(
  select 0 lvl, membernum, sevrfromdate
    , nextdate
  from  t
  where sevrfromdate=(select min(sevrfromdate)
             from #tmp1 t2 where t2.membernum=t.membernum) 
  union all
  select lvl+1,t.membernum, t.sevrfromdate
    ,t.nextdate
  from r inner join t on r.membernum=t.membernum
     and t.sevrfromdate=r.nextdate
) 
select t.membernum, t.sevrfromdate
  ,case when r.sevrfromdate is not null then 1 else 0 end flag
  ,r.nextdate as next_date
from #tmp1 t
left join r on r.membernum=t.membernum
   and r.sevrfromdate=t.sevrfromdate

номер члена sevrfromdate флаг следующая_дата 1000016 13 апреля 2022 г. 1 20 апреля 2022 г. 1000016 15 апреля 2022 г. 0 нулевой 1000016 20 апреля 2022 г. 1 2022-04-28 1000016 2022-04-22 0 нулевой 1000016 2022-04-23 0 нулевой 1000016 2022-04-28 1 нулевой

рабочий пример

Результат рекурсивного запроса

уровень номер члена sevrfromdate следующая дата 0 1000016 13 апреля 2022 г. 20 апреля 2022 г. 1 1000016 20 апреля 2022 г. 2022-04-28 2 1000016 2022-04-28 нулевой

Работает как шарм. Спасибо!

batoni 02.08.2024 22:41

Другие вопросы по теме