间隙和岛屿分组

问题描述 投票:0回答:1

对于我的源表,我以正确的顺序保存了所有“客户的联系历史记录”(从顶部最早的日期开始升序)。我需要做的是将联系人与同一问题相关的行分组。判断一个问题是否相关的方法是根据时间。如果时差<2 weeks then the two cases are related.

“通过或失败”列中的 1 突出显示案例是否已完全解决。 0 表示来自下一行的调用与同一问题相关。

我需要生成此表的摘要,以显示客户针对同一查询多次联系的位置

我正在使用 SQL Server 2012

这是我的源数据的示例。在我的完整表中,我将有多个客户。您可以看到我用颜色编码来显示总共 9 个联系人,但只有 4 个不同的问题。每个客户的联系次数或问题没有固定数量

客户_ID 开始日期 下一个_日期 时差_(分钟) 联系人总数 通过或失败 NEXT_Contact_same_day
12345 2022年3月3日 2022年5月5日 90794 1 1 0
12345 2022年5月5日 2022年5月5日 3 1 0 1
12345 2022年5月5日 2022年6月5日 1409 1 0 0
12345 2022年6月5日 2022年6月5日 2 1 0 1
12345 2022年6月5日 2022年6月5日 11 1 0 1
12345 2022年6月5日 20/11/2022 284973 1 1 0
12345 20/11/2022 2023年5月1日 66242 1 1 0
12345 2023年5月1日 2023年5月1日 178 1 0 1
12345 2023年5月1日 1 1 0

我尝试在“通过”或“失败”列上使用 DENSE_RANK、ROW_NUMBER、LAG&LEAD,以及开始日期和下一个日期的最大和最小日期,但没有任何运气。

例如

select Customer ID, sum(total_contacts), min(Start date), max(Next Date)
from (select *,
             sum(case when Pass or fail = 0 then 1 else 0 end) over (order by Customer ID) as grp
      from #Mastery
     ) #Mastery
where total_contacts = '1'
group by Customer ID, grp;

-- 这将返回所有联系人

select Customer ID, sum(total_contacts) AS total_Contacts, SUM (Pass or fail) AS Pass#, min(Start date) AS Mindate, max(Next Date) AS Maxdate, 
       ROW_NUMBER () over(partition by Customer ID order by Pass or fail) as Contactranking
from  #Mastery2
group by Customer ID,  Pass or fail

-- 这仅返回通过和失败的总和

这是我正在寻找的输出。您可以看到,针对相同的客户 ID,我有 4 行,一行代表每个问题。对于每一行,它应该显示针对该问题的调用数量。要量化与同一问题相关的呼叫数量,您必须使用“通过或失败”列

sql-server sql-server-2012 difference
1个回答
0
投票

这是一个间隙和岛式问题,您对分组有正确的想法,但有一些细节使这有点棘手。这是一个潜在的解决方案:

SELECT  CustomerID, MIN(startDate) startDate, NULLIF(MAX(nextDate), '99991231') nextDate, COUNT(*) cnt
FROM    (
    select  *
    ,   SUM(passprev) OVER(partition by customerid order by startDate, nextdate) AS grp
    from (
        
        select  LAG(passorfail, 1, 0) over(partition by customerid order by d.startDate,  d.nextDate) AS passprev
        ,   d.*
        ,   customerID
        from (
            VALUES  (12345, N'03/03/2022', N'05/05/2022', N'90794', 1, 1, 0)
            ,   (12345, N'05/05/2022', N'05/05/2022', N'3', 1, 0, 1)
            ,   (12345, N'05/05/2022', N'06/05/2022', N'1409', 1, 0, 0)
            ,   (12345, N'06/05/2022', N'06/05/2022', N'2', 1, 0, 1)
            ,   (12345, N'06/05/2022', N'06/05/2022', N'11', 1, 0, 1)
            ,   (12345, N'06/05/2022', N'20/11/2022', N'284973', 1, 1, 0)
            ,   (12345, N'20/11/2022', N'05/01/2023', N'66242', 1, 1, 0)
            ,   (12345, N'05/01/2023', N'05/01/2023', N'178', 1, 0, 1)
            ,   (12345, N'05/01/2023', NULL, NULL, 1, 1, 0)
        ) t (CustomerID,Startdate,NextDate,[TimeDifference(Mins)],total_contacts,Passorfail,[NEXT_Contact_same_day])
        CROSS APPLY (
                SELECT  CONVERT(DATETIME, startdate, 103) AS startDate
                ,   ISNULL(CONVERT(DATETIME, NextDate, 103), '99991231') AS nextDate
            ) d
        ) x
    ) x
GROUP BY customerID, grp

首先也是最重要的,问题是你必须获取之前的

passorfail
列,因为通常当你创建间隙和岛屿总和时,你希望将值保持为 0,直到新的组到达,而这里为 1创建一个新组。因此我使用
LAG(passorfail, 1, 0)

这里的排序也有点棘手,因为你有多个重复的日期。为此,我通过

ISNULL(CONVERT(DATETIME, NextDate, 103), '99991231')
创建了决胜局,以便开放日期结束。它还简化了以后的 MAX 处理。

其余的没什么特别的,除了我们用

NULLIF(MAX(nextDate), '99991231')

将日期翻转回空

几点注意:您应该以表格格式提供测试数据。另外,DD/MM/YYYY 是一种非常不方便的日期样式,YYYYMMDD 更好。

© www.soinside.com 2019 - 2024. All rights reserved.