Возьмите данные из записи интереса, когда условие или критерии фильтра совпадают, и игнорируйте записи между текущей строкой и выбранной записью (строкой интереса)

Как написать CTE в SQL Server, чтобы получить дату из предыдущей строки для человека с типом = NA.

Если имеется несколько предыдущих строк с NA, при сортировке по возрастанию dt_eff выберите первую.

Если между началом записи и типом = NA есть какие-либо другие типы, то эти записи следует игнорировать. Рассматривайте другие типы для того же человека только после того, как предыдущий тип закончился (сценарий «Лица 124»).

Источник данных

Person    Type     dt_eff
123       A        2018-10-23 <Start of record >
123       NA       2018-11-19 <Should be the end date for above and dont select this in output> 
123       NA       2018-12-25 <dont select this in output>
124       A        2020-01-01 <Start of record >
124       B        2020-02-15 <Ignore and dont select in output>
124       NA       2020-05-14 <Should be the end date for start of record and dont select in op>
124       C        2020-10-13 <As the above start record has ended this should be new start>
124       NA       2021-01-15 <should be the end date for second start record>
124       A        2021-05-22 <As the above start record has ended this should be new start>
124       T        2021-08-22 <Ignored and dont select in output>
456       NA       2022-04-19 <Ignore as there is no lag record with valid type>
456       A        2022-05-01 <Start of record and null as end date as there is no type = NA>
456       B        2022-07-15 <Ignore>

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

Person    Type     dt_start     dt_end
123       A        2018-10-23   2018-11-19
124       A        2020-01-01   2020-05-14
124       C        2020-10-13   2021-01-15
124       A        2021-05-22   NULL
456       A        2022-05-01   NULL

DML и DDL для вышеуказанных исходных данных

CREATE TABLE Person (
  Person INTEGER,
  Type VARCHAR(3),
  dt_eff Date
);

INSERT INTO Person (Person, Type, dt_eff)
VALUES
(123,'A','2018-10-23'),
(123,'NA','2018-11-19'),
(123,'NA','2018-12-25'),
(124,'A','2020-01-01'),
(124,'B','2020-02-15'),
(124,'NA','2020-05-14'),
(124,'C','2020-10-13'),
(124,'NA','2021-01-15'),
(124,'A','2021-05-22'),
(124,'T','2021-08-22'),
(456,'NA','2022-04-19'),
(456,'A','2022-05-01'),
(456,'B','2022-07-15')

Пытаться

with cte1 as (
  select *
    , lead(dt_eff) over (partition by Person order by dt_eff) dt_eff_lead
    , lag(Type, 1, Type) over (partition by Person order by dt_eff) type_lag
  from Person
), cte2 as (
  select Person, Type, dt_eff Start_Date
    , dt_eff_lead
    , sum(case when Type <> type_lag and type='NA' then 1 else 0 end)
      over (partition by person order by dt_eff asc
        rows between unbounded preceding and current row) TypeGroup
  from cte1
)
select Person, Type, Start_Date as dt_start
  , max(dt_eff_lead) over (partition by Person, TypeGroup) dt_end
from cte2
where Type<>'NA'
order by Person, Start_Date, Type;

Включен дополнительный фильтр (type='NA') в запрос, который вы указали во вчерашнем сообщении. sum (случай, когда Type <> type_lag и Type='NA', затем 1, иначе 0 end)». Это дает дату окончания предыдущей записи, где type='NA'. Но не уверен, насколько эффективно мы можем фильтровать записи и заканчивать дата равна нулю, если нет предыдущей записи с типом = NA

skv 15.05.2024 00:26

Добавлен запрос. нужен столбец короля флагов в cte2, где написано игнорировать эту запись + dt_end должен быть нулевым для начальной записи, когда нет предыдущей записи с типом = NA

skv 15.05.2024 00:49

Рекомендую присмотреться к гэпам и островам

Dale K 15.05.2024 02:55
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
3
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете выполнить группировку на основе общего количества строк NA:

SELECT  Person, Type
,   dt_start, CASE WHEN cntNA > 0 THEN dt_end END AS dt_end
FROM    (
    SELECT  MIN(dt_eff) OVER(PARTITION BY person, grouping) AS dt_start
    ,   MAX(dt_eff) OVER(PARTITION BY person, grouping) AS dt_end
    ,   COUNT(CASE WHEN type = 'NA' THEN 1 END) OVER(PARTITION BY person, grouping) AS cntNA
    ,   ROW_NUMBER() OVER(PARTITION BY person, grouping ORDER BY dt_eff) AS startrow
    ,   *
    FROM    (
        SELECT  *
        ,   COUNT(CASE WHEN Type = 'NA' THEN 1 END) OVER(PARTITION BY Person ORDER BY dt_eff ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS grouping
        FROM
        (
            VALUES  (123, N'A', N'2018-10-23')
            ,   (123, N'NA', N'2018-11-19')
            ,   (123, N'NA', N'2018-12-25')
            ,   (124, N'A', N'2020-01-01')
            ,   (124, N'B', N'2020-02-15')
            ,   (124, N'NA', N'2020-05-14')
            ,   (124, N'C', N'2020-10-13')
            ,   (124, N'NA', N'2021-01-15')
            ,   (124, N'A', N'2021-05-22')
            ,   (124, N'T', N'2021-08-22')
            ,   (456, N'NA', N'2022-04-19')
            ,   (456, N'A', N'2022-05-01')
            ,   (456, N'B', N'2022-07-15')
        ) t (Person,Type,dt_eff)
    ) x
) x
WHERE   startrow = 1
AND type <> 'NA'
  1. COUNT(CASE WHEN Type = 'NA' THEN 1 END) OVER(PARTITION BY Person ORDER BY dt_eff ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) создает указанное выше значение группировки. AND 1 PRECEDING означает, что первая NA засчитывается по отношению к предыдущим строкам, и это то, что вам нужно для группировки.

  2. Затем вы создаете минимальную/максимальную дату для каждой группы, а также определяете, какая строка является первой, поскольку вас интересует только одна строка на группу. cntNA содержит количество NA в группе, так как вам нужно обнулить dt_end для тех, у кого нет NA.

  3. Наконец, вы выбираете то, что ищете. CASE WHEN cntNA > 0 THEN dt_end END создает открытые даты

Ух ты. Подпадает ли эта группа под «разрыв и остров»? кто-то посоветовал мне изучить пробел и группировку островов. Для меня ваш запрос выглядит как разрыв и группировка островов. Изучение новых вещей. Это работает так, как и ожидалось, и очень эффективно. Буду тестировать на больших данных. Спасибо.

skv 15.05.2024 15:28

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

siggemannen 15.05.2024 16:24

Спасибо. очень полезно. вместе с cte начну искать пробелы и остров.

skv 15.05.2024 18:40

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