【问题标题】:Extending end date then compare repeatedly延长结束日期然后反复比较
【发布时间】:2018-11-17 04:30:05
【问题描述】:

我想做的是扩展RxEndDates,直到处方中不再有重叠。并且新的扩展也不重叠。

上下文:如果 Amy 每天服用 Humera 并在她当前的处方用完之前补加药,则将第 2 个处方的 DaySupply 添加到第一个处方中。

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!     

有没有办法在循环中自动执行此操作...有什么想法吗?

【问题讨论】:

  • 您使用的是什么版本的 SQL Server?
  • @rosie chi:你不觉得这个问题应该是mergedyour other one吗?我一直在测试这些解决方案,但在我看来,只有递归才能完成这项工作。在那篇文章中,我已经展示了一个实现,因此其他人在编写相同的代码之前也应该看到它。
  • @DávidLaczkó:我认为这是个好主意!我已阅读您指出的“合并”链接,但看起来我无法进行合并,只有版主。您是否有可能在此处发布该帖子中的答案?
  • @aduguid:我想这很重要...我使用的是 SQL Server 2008。谢谢!
  • 好的,我在这里复制了我的答案。还将另一个问题标记为已关闭(此后没有添加任何内容)。

标签: sql sql-server loops


【解决方案1】:

我认为该解决方案只能通过递归来实现,因为应该有一个循环来计算累积的 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.:如果我添加“Amy”、“Humera”、“2/15/2017”、“11”、“2/25/2017”,这个也可以工作,我用它来批评其他解决方案。 .. 我很好奇它是否按您的预期工作 - 请测试!

【讨论】:

  • 哇哦!此解决方案适用于 SQL Server 2008。我做了一个微小的更改...在比较 2 个 dateadds 时,在最后一个 '
  • 你的意思是这一行应该有
  • 这是一个很好的更正,我更新了帖子。感谢您的反馈!
【解决方案2】:

您可以使用not exists 确定组的起点。然后做一个累积和分配一个组。 . .和聚合。下面假设一个唯一的 id,这是处理重复项所需要的:

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;

【讨论】:

  • 感谢您的回复...当我运行代码时,我收到以下错误代码:'order' 附近的语法不正确,'t' 附近的语法不正确...我觉得这是这么近,你介意帮我看看是怎么回事吗?你的代码很难让我理解:-)
  • 好的,所以我已经删除了窗口函数中的 ORDER BY,因为我不确定它是否必要(也许是?)现在错误是:'grp' 附近的语法不正确在 GROUP BY 之后
  • 另外,我的数据结构是这样的接收开始日期
  • @rosiechi 。 . . order by 对窗口函数非常关键。否则,grp 设置不正确。
  • 谢谢!我只是按部分阅读了订单,发现我的服务器不支持此功能,这就是我收到错误的原因!
【解决方案3】:

我使用CTE Common Table Expression 来执行分组。由于某些日子在技术上并不重叠,因此我通过在source_data 中的[RxEndDate] 中添加1 来创建备用结束日期[RxEndDate_ALT]。然后我可以在source_data_grouped 中使用NOT EXISTS 对日期进行分组。之后,我又加入了source_data_rawSUM[DaySupply]


结果


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]

【讨论】:

  • 这似乎没有返回正确的日用品。这与 Gordon Linoff 的问题相同:此解决方案恰好适用于样本数据,但如果我添加 'Amy'、'Humera'、'2/15/2017'、'11'、'2/25/ 2017',我没有得到只有一个连续间隔的正确结果。它说我有 2 个间隔,一个 18 天,一个 91 天。如果将 18-1 天添加到 2017 年 2 月 12 日,它将变为 2017 年 3 月 1 日,这是与 2017 年 2 月 28 日的新重叠。我认为非递归方法在一般情况下不起作用,因为需要跟踪累积的重叠天数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-09
  • 1970-01-01
  • 2017-02-08
  • 1970-01-01
  • 1970-01-01
  • 2014-10-31
  • 2019-07-08
相关资源
最近更新 更多