Продление даты окончания и последующее сравнение - PullRequest
0 голосов
/ 15 ноября 2018

Что я хотел бы сделать, это продлить RxEndDates до тех пор, пока в рецептах больше не будет совпадений.И новые расширения также не перекрываются.

Контекст: если Эми ежедневно принимает Humera и получает добавку до того, как закончится ее текущий рецепт, то добавьте DaySupply 2-го рецепта к первому рецепту.

sample data:
User Drug   RxStartDate DaySupply   RxEndDate
Amy Humera  2/12/2017   7   2/18/2017
Amy Humera  2/28/2017   5   3/4/2017 <--Overlap with below
Amy Humera  3/3/2017    5   3/7/2017 <--Overlap with above, need to combine
Amy Humera  3/8/2017    2   3/9/2017
Amy Humera  3/10/2017   7   3/16/2017
Amy Humera  3/17/2017   30  4/15/2017 <--Overlap with all below, combine
Amy Humera  3/22/2017   2   3/23/2017 <--Overlap
Amy Humera  3/24/2017   2   3/25/2017 <--Overlap
Amy Humera  3/31/2017   3   4/2/2017  <--Overlap
Amy Humera  4/7/2017    5   4/11/2017 <--Overlap
Amy Humera  4/13/2017   30  5/12/2017 <--Overlap

Итак, после объединения мы получим

User Drug   RxStartDate DaySupply   RxEndDate
Amy Humera  2/12/2017   7   2/18/2017
Amy Humera  2/28/2017   10  3/9/2017 <-- Combined from above, new overlap
Amy Humera  3/8/2017    2   3/9/2017 <-- Now this overlaps with above
Amy Humera  3/10/2017   7   3/16/2017
Amy Humera  3/17/2017   72  5/27/2017

User Drug   RxStartDate DaySupply   RxEndDate
Amy Humera  2/12/2017   7   2/18/2017
Amy Humera  2/28/2017   12  3/11/2017 <-- Combined, again, new overlap
Amy Humera  3/10/2017   7   3/16/2017 <-- Now this overlaps with above
Amy Humera  3/17/2017   72  5/27/2017

User Drug   RxStartDate DaySupply   RxEndDate
Amy Humera  2/12/2017   7   2/18/2017
Amy Humera  2/28/2017   19  3/18/2017 <-- Combined, again, new overlap
Amy Humera  3/17/2017   72  5/27/2017 <-- Now this overlaps with above

User Drug   RxStartDate DaySupply   RxEndDate
Amy Humera  2/12/2017   7   2/18/2017
Amy Humera  2/28/2017   91  5/29/2017
There is no more overlap…finished!     

Есть ли способ сделать это автоматически в цикле или что-то ... какие-нибудь идеи?

Ответы [ 3 ]

0 голосов
/ 16 ноября 2018

Я использовал Общее выражение таблицы CTE для выполнения группировки. Поскольку некоторые дни технически не перекрываются, я создал альтернативную дату окончания [RxEndDate_ALT], добавив 1 к [RxEndDate] в source_data. Затем я смог сгруппировать даты, используя NOT EXISTS в source_data_grouped. После этого я присоединяюсь к source_data_raw к SUM [DaySupply].


Результаты

screenshot


SQL

WITH 
source_data_raw
AS 
(
    SELECT tbl.* FROM (VALUES
      ( 'Amy', 'Humera', 7, CAST('12-Feb-2017' AS DATE), CAST('18-Feb-2017' AS DATE))
    , ( 'Amy', 'Humera', 5, '28-Feb-2017', '04-Mar-2017')
    , ( 'Amy', 'Humera', 5, '03-Mar-2017', '07-Mar-2017')
    , ( 'Amy', 'Humera', 2, '08-Mar-2017', '09-Mar-2017')
    , ( 'Amy', 'Humera', 7, '10-Mar-2017', '16-Mar-2017')
    , ( 'Amy', 'Humera', 30, '17-Mar-2017', '15-Apr-2017')
    , ( 'Amy', 'Humera', 2, '22-Mar-2017', '23-Mar-2017')
    , ( 'Amy', 'Humera', 2, '24-Mar-2017', '25-Mar-2017')
    , ( 'Amy', 'Humera', 3, '31-Mar-2017', '15-Apr-2017')
    , ( 'Amy', 'Humera', 5, '07-Apr-2017', '16-Apr-2017')
    , ( 'Amy', 'Humera', 30, '13-Apr-2017', '27-May-2017')
    ) tbl ([User], [Drug], [DaySupply], [RxStartDate], [RxEndDate]) 
) 
, 
source_data
AS
(
    SELECT 
          sdr.[User]
        , sdr.[Drug]
        , sdr.[RxStartDate]
        , sdr.[RxEndDate]
        , [RxEndDate_ALT] = DATEADD(DAY, 1, sdr.[RxEndDate])
    FROM 
        source_data_raw AS sdr
)
, 
source_data_grouped
AS
(
    SELECT 
          s1.[User]
        , s1.[Drug]
        , s1.[RxStartDate]
        , [RxEndDate] = MIN(t1.[RxEndDate]) 
    FROM 
        source_data AS s1 
        INNER JOIN source_data AS t1 ON s1.[User] = t1.[User] AND s1.[Drug] = t1.[Drug] AND s1.[RxStartDate] <= t1.[RxEndDate_ALT]
            AND NOT EXISTS 
                (
                    SELECT 1
                    FROM source_data AS t2
                    WHERE 
                        1=1
                        AND t1.[User] = t2.[User]
                        AND t1.[Drug] = t2.[Drug]
                        AND t1.[RxEndDate_ALT] >= t2.[RxStartDate]
                        AND t1.[RxEndDate_ALT] < t2.[RxEndDate_ALT]
                ) 
    WHERE 
        1=1
        AND NOT EXISTS 
        (
            SELECT 1
            FROM source_data AS s2
            WHERE 
                1=1
                AND s1.[User] = s2.[User]
                AND s1.[Drug] = s2.[Drug]
                AND s1.[RxStartDate] > s2.[RxStartDate]
                AND s1.[RxStartDate] <= s2.[RxEndDate_ALT]
        )
    GROUP BY 
          s1.[User]
        , s1.[Drug]
        , s1.[RxStartDate]
)
SELECT 
      sdg.[User]
    , sdg.[Drug]
    , [DaySupply] = SUM(sdr.[DaySupply])
    , sdg.[RxStartDate]
    , sdg.[RxEndDate]
FROM 
    source_data_grouped AS sdg
    INNER JOIN source_data_raw AS sdr ON sdr.[RxStartDate] BETWEEN sdg.[RxStartDate] AND sdg.[RxEndDate]
GROUP BY 
      sdg.[User]
    , sdg.[Drug]
    , sdg.[RxStartDate]
    , sdg.[RxEndDate]
0 голосов
/ 16 ноября 2018

Я думаю, что решение может быть реализовано только с помощью рекурсии, поскольку должен быть цикл, который вычисляет накопленный DaySupply, и я не вижу способа сделать это с любыми нерекурсивными поисками.Вы можете сделать это с помощью рекурсивного CTE - и, согласно официальному документу, оно доступно начиная с SQL Server 2008.
Возможная реализация (я добавил несколько тестовых данных, чтобы проверить это):

DECLARE @test TABLE (
    [User] VARCHAR(100),
    Drug VARCHAR(100),
    RxStartDate DATE,
    DaySupply INT,
    RxEndDate DATE
)

INSERT @test
VALUES
    ('Amy', 'Humera', '2/12/2017', '7', '2/18/2017'),
    ('Amy', 'Humera', '2/28/2017', '5', '3/4/2017'),
    ('Amy', 'Humera', '3/3/2017', '5', '3/7/2017'),
    ('Amy', 'Humera', '3/8/2017', '2', '3/9/2017'),
    ('Amy', 'Humera', '3/10/2017', '7', '3/16/2017'),
    ('Amy', 'Humera', '3/17/2017', '30', '4/15/2017'),
    ('Amy', 'Humera', '3/22/2017', '2', '3/23/2017'),
    ('Amy', 'Humera', '3/24/2017', '2', '3/25/2017'),
    ('Amy', 'Humera', '3/31/2017', '3', '4/2/2017'),
    ('Amy', 'Humera', '4/7/2017', '5', '4/11/2017'),
    ('Amy', 'Humera', '4/13/2017', '30', '5/12/2017'),

    ('Amy', 'Other', '3/24/2017', '7', '3/30/2017'),
    ('Amy', 'Other', '3/31/2017', '3', '4/2/2017'),
    ('Amy', 'Other', '4/7/2017', '5', '4/11/2017'),
    ('Amy', 'Other', '4/13/2017', '30', '5/12/2017'),

    ('Joe', 'Humera', '3/24/2017', '8', '3/31/2017'),
    ('Joe', 'Humera', '3/31/2017', '3', '4/2/2017'),
    ('Joe', 'Humera', '4/12/2017', '5', '4/16/2017'),
    ('Joe', 'Humera', '4/23/2017', '30', '5/22/2017'),

    ('Joe', 'Other', '3/24/2017', '60', '5/23/2017'),
    ('Joe', 'Other', '3/31/2017', '3', '4/2/2017'),
    ('Joe', 'Other', '4/7/2017', '5', '4/11/2017'),
    ('Joe', 'Other', '4/13/2017', '30', '5/12/2017')



-- You can comment this out, it is just to show progress:
SELECT * FROM @test ORDER BY [User], Drug, RxStartDate



DECLARE @test_2 TABLE (
    [User] VARCHAR(100),
    Drug VARCHAR(100),
    RxStartDate_base DATE,
    DaySupplyCumulative INT
)

;WITH CTE_RxEndDateExtended as (
    SELECT [User], Drug, RxStartDate, DaySupply, DaySupply as DaySupplyCumulative, RxStartDate as RxStartDate_base, RxStartDate as RxStartDateExtended, dateadd (dd, DaySupply, RxStartDate) as RxEndDateExtended
    FROM @test
    -- WHERE [User] = 'Amy' and Drug = 'Humera' and RxStartDate = '2/28/2017'
    UNION ALL
    SELECT t.[User], t.Drug, t.RxStartDate, t.DaySupply, c.DaySupplyCumulative + t.DaySupply as DaySupplyCumulative, c.RxStartDate_base, t.RxStartDate as RxStartDateExtended, dateadd (dd, t.DaySupply, c.RxEndDateExtended) as RxEndDateExtended
    FROM CTE_RxEndDateExtended as c INNER JOIN @test as t
        on c.[User] = t.[User] and c.Drug = t.Drug
            and c.RxEndDateExtended >= t.RxStartDate and c.RxStartDateExtended < t.RxStartDate
)
INSERT @test_2
SELECT [User], Drug, RxStartDate_base, MAX (DaySupplyCumulative) as DaySupplyCumulative -- comment this out and use this for debugging: SELECT *
FROM CTE_RxEndDateExtended
GROUP BY [User], Drug, RxStartDate_base -- comment this out for debugging
OPTION (MAXRECURSION 0) -- comment this out and use this for debugging (to avoid infinite loops): OPTION (MAXRECURSION 1000)



-- You can comment this out, it is just to show progress:
SELECT * FROM @test_2
ORDER BY [User], Drug, RxStartDate_base -- comment this out and use this for debugging: ORDER BY [User], Drug, RxStartDate_base, RxStartDate, DaySupplyCumulative



SELECT base.*, dateadd (dd, base.DaySupplyCumulative - 1, base.RxStartDate_base) as RxEndDateCumulative
FROM @test_2 as base LEFT OUTER JOIN @test_2 as filter
    on base.[User] = filter.[User] and base.Drug = filter.Drug
        and base.RxStartDate_base > filter.RxStartDate_base
        and dateadd (dd, base.DaySupplyCumulative, base.RxStartDate_base) <= dateadd (dd, filter.DaySupplyCumulative, filter.RxStartDate_base)
WHERE filter.[User] IS NULL
ORDER BY [User], Drug, RxStartDate_base

Может быть, вам нужно оптимизировать его, упростив логику.Но будьте осторожны, чтобы не сделать бесконечный цикл.При отладке используйте OPTION (MAXRECURSION N ) с N отличным от нуля.

PS .: этот работает также, если я добавлю «Эми», «Хумера», «15.02.2017», «11», «25.02.2017», с которыми я критиковалдругие решения ... Мне любопытно, если это работает, как вы ожидаете - пожалуйста, проверьте!

0 голосов
/ 15 ноября 2018

Вы можете определить, где начинается группа, используя not exists.Затем выполните накопительную сумму, чтобы назначить группу.,,и совокупность.Следующее предполагает наличие уникального идентификатора, который необходим для обработки дубликатов:

select [user], drug, grp, sum(daysupply), min(RxStartDate), max(RxEndDate)
    from (select t.*, sum(flg) over (partition by [user], drug order by RxStartDate) as grp
          from (select t.*,
                       (case when exists (select 1
                                          from @test t2
                                          where t2.[user] = t.[user] and t2.drug = t.drug and
                                                t2.RxStartDate < t.RxStartDate and
                                                t2.RxEndDate >= dateadd(day, -1, t.RxStartDate)
                                         )
                             then 0 else 1
                        end) as flg
                from @test t
               ) t
          ) t
    group by [user], drug, grp;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...