Sql 查找缺少的联系日期详细信息

Sql 查找缺少的联系日期详细信息,sql,sql-server,sql-server-2008-r2,Sql,Sql Server,Sql Server 2008 R2,我有下表和联系人详细信息: 表:TBL合同 样本数据: INSERT INTO tblContacts VALUES(12,123456,'2019-01-01'); INSERT INTO tblContacts VALUES(3,3456,'2019-01-01'); INSERT INTO tblContacts VALUES(12,123560,'2019-01-02'); INSERT INTO tblContacts VALUES(12,123459,'2019-01-05'); I

我有下表和联系人详细信息:

表:TBL合同

样本数据:

INSERT INTO tblContacts VALUES(12,123456,'2019-01-01');
INSERT INTO tblContacts VALUES(3,3456,'2019-01-01');
INSERT INTO tblContacts VALUES(12,123560,'2019-01-02');
INSERT INTO tblContacts VALUES(12,123459,'2019-01-05');
INSERT INTO tblContacts VALUES(3,3446,'2019-01-02');
INSERT INTO tblContacts VALUES(3,3486,'2019-01-03');
INSERT INTO tblContacts VALUES(3,34861,'2019-01-05');
INSERT INTO tblContacts VALUES(3,34862,'2019-01-07');
INSERT INTO tblContacts VALUES(12,127456,'2019-01-21');
INSERT INTO tblContacts VALUES(12,129456,'2019-02-03');
INSERT INTO tblContacts VALUES(12,126456,'2019-02-06');
INSERT INTO tblContacts VALUES(94,941256,'2019-01-01');
INSERT INTO tblContacts VALUES(94,944356,'2019-01-03');
INSERT INTO tblContacts VALUES(94,941356,'2019-01-07');
INSERT INTO tblContacts VALUES(94,943356,'2019-01-09');

我想找到那些从未在这些日期和通话前后1或2天打过电话的联系人

注意:我可能会在通话前后折皱到任何级别,如1、2、3、4等

预期输出:调用前后仅1天的以下输出

ContacNumber    CDate
----------------------------------------
3486            2019-01-03
NULL            2019-01-04
34861           2019-01-05
NULL            2019-01-06
34862           2019-01-07
123560          2019-01-02
NULL            2019-01-03 - 2019-01-04
123459          2019-01-05
NULL            2019-01-06 - 2019-01-20
127456          2019-01-21
NULL            2019-01-22 - 2019-02-02
129456          2019-02-03
NULL            2019-02-04 - 2019-02-05
126456          2019-02-06
941256          2019-01-01
NULL            2019-01-02
944356          2019-01-03
NULL            2019-01-04 - 2019-01-06
941356          2019-01-07
NULL            2019-01-08
943356          2019-01-09
My try:以下查询仅适用于通话前后1天,但不适用于1天以外的时间

查询:

; WITH Stage_1_CTE AS
(
    SELECT  Series,
            ContacNumber,
            CAST(CDate AS DATE) CDate,
            ROW_NUMBER() OVER (PARTITION BY Series ORDER BY CAST(CDate AS DATE)) rnk1,
            (ROW_NUMBER() OVER (PARTITION BY Series ORDER BY CAST(CDate AS DATE)))/2 rnk2,
            (ROW_NUMBER() OVER (PARTITION BY Series ORDER BY CAST(CDate AS DATE)) + 1)/2 rnk3
    FROM tblContacts
    GROUP BY ContacNumber,CDate,Series
)
,
Stage_2_CTE AS
(
    SELECT *,
           CASE WHEN rnk1%2=1 THEN MAX(CASE WHEN rnk1%2=0 THEN CDate END) OVER (PARTITION BY Series,rnk2) 
                ELSE MAX(CASE WHEN rnk1%2=1 THEN CDate END) OVER (PARTITION BY Series,rnk3)
           END AS CDate_Prev,
           CASE WHEN rnk1%2=1 THEN MAX(CASE WHEN rnk1%2=0 THEN CDate END) OVER (PARTITION BY Series,rnk3) 
                ELSE MAX(CASE WHEN rnk1%2=1 THEN CDate END) OVER (PARTITION BY Series,rnk2)
           END AS CDate_Next
    FROM Stage_1_CTE
) 
,Stage_Final_CTE AS
(
    SELECT c.Series,
           c.ContacNumber, 
           c.CDate, 
           EndDate = ''
    FROM Stage_2_CTE c
    WHERE c.CDate <> DATEADD(DAY, +1, CDate_Prev) OR c.CDate <> DATEADD(DAY, -1, CDate_Next)
    UNION ALL
    SELECT Series,
           ContacNumber = NULL,
           CDate = DATEADD(DAY, 1, c.CDate),
           EndDate = ' - '+CAST(DATEADD(DAY, -1, CDate_Next) AS VARCHAR(10))
    FROM Stage_2_CTE c
    WHERE c.CDate <> DATEADD(DAY, -1, CDate_Next)
)
SELECT  ContacNumber, 
        CASE WHEN CAST(CDate AS VARCHAR(10)) =  REPLACE(EndDate,' - ','')  
        THEN CAST(CDate AS VARCHAR(10))
        ELSE
            CAST(CDate AS VARCHAR(10)) + CAST(EndDate AS VARCHAR(13))
        END CDate
FROM Stage_Final_CTE
GROUP BY ContacNumber,CDate,EndDate,Series
ORDER BY Series,CDate;  

您可以生成数字,然后添加行。大概是这样的:

select contactnumber, cdate, 1 as isvalid
from tblcontacts
union all
select c.contactnumber, dateadd(day, v.n, c.contacctdate), 0
from tblcontacts c cross join
     (values (-1), (1)) v(n)
where not exists (select 1
                  from tblcontacts c2
                  where c2.contactnumber = c.contactnumber and
                        c2.date = dateadd(day, v.n, c.contacctdate)
                 );

注意:我添加了一个新列来确定行是否有效。在第一列中重复NULL值没有意义,因为您不知道该行适用于哪个联系人号码。

您可以生成号码,然后添加行。大概是这样的:

select contactnumber, cdate, 1 as isvalid
from tblcontacts
union all
select c.contactnumber, dateadd(day, v.n, c.contacctdate), 0
from tblcontacts c cross join
     (values (-1), (1)) v(n)
where not exists (select 1
                  from tblcontacts c2
                  where c2.contactnumber = c.contactnumber and
                        c2.date = dateadd(day, v.n, c.contacctdate)
                 );

注意:我添加了一个新列来确定行是否有效。在第一列中重复空值是没有意义的,因为您不知道该行适用于哪一个联系人号码。

您可以获得一系列中的下一个日期

可以用来找出日期之间的差距

然后将这些间隙粘合到结果上

对于Sql Server 2008,数据首先加载到临时表中

IF OBJECT_ID('tempdb..#tmpContacts', 'U') IS NOT NULL
    DROP TABLE #tmpContacts; 

CREATE TABLE #tmpContacts
(
 Series INT NOT NULL,
 Rn INT NOT NULL,
 ContacNumber INT NOT NULL,
 CDate DATE NOT NULL,
 PRIMARY KEY (Series, Rn)
); 

INSERT INTO #tmpContacts (Series, ContacNumber, CDate, Rn)
SELECT Series, ContacNumber
, CAST(CDate AS DATE)
, ROW_NUMBER() OVER (PARTITION BY Series ORDER BY CAST(CDate AS DATE)) Rn
FROM tblContacts
WHERE CDate >=  CAST('2019-01-01' AS DATE)
    AND CAST(CDate AS DATE) <=  EOMONTH(EOMONTH(CAST('2019-01-01' AS DATE)))
  GROUP BY Series, ContacNumber, CAST(CDate AS DATE);

WITH CTE_CONTACTS AS
(
  SELECT Series, ContacNumber
  , CDate
  , CDate AS nextCDate
  , CAST(0 AS BIT) AS IsGap
  FROM #tmpContacts

  UNION ALL

  SELECT t1.Series, null
  , DATEADD(day,1,t1.CDate)
  , DATEADD(day,-1,t2.CDate)
  , 1
  FROM #tmpContacts t1
  LEFT JOIN #tmpContacts t2
    ON t2.Series = t1.Series
   AND t2.Rn = t1.Rn + 1
   AND t1.CDate < DATEADD(day,-1,t2.CDate)
)
SELECT c.Series, ContacNumber
, CONCAT(CONVERT(varchar,c.CDate,23), 
        CASE 
        WHEN c.IsGap=1
         AND DATEDIFF(day,c.CDate,c.nextCDate) > 0 
        THEN ' - ' + CONVERT(varchar,c.nextCDate,23) 
        END) AS Cdates
FROM CTE_CONTACTS c
ORDER BY c.Series, c.CDate;
雷克斯试验机的试验


你可以得到一系列的下一次约会

可以用来找出日期之间的差距

然后将这些间隙粘合到结果上

对于Sql Server 2008,数据首先加载到临时表中

IF OBJECT_ID('tempdb..#tmpContacts', 'U') IS NOT NULL
    DROP TABLE #tmpContacts; 

CREATE TABLE #tmpContacts
(
 Series INT NOT NULL,
 Rn INT NOT NULL,
 ContacNumber INT NOT NULL,
 CDate DATE NOT NULL,
 PRIMARY KEY (Series, Rn)
); 

INSERT INTO #tmpContacts (Series, ContacNumber, CDate, Rn)
SELECT Series, ContacNumber
, CAST(CDate AS DATE)
, ROW_NUMBER() OVER (PARTITION BY Series ORDER BY CAST(CDate AS DATE)) Rn
FROM tblContacts
WHERE CDate >=  CAST('2019-01-01' AS DATE)
    AND CAST(CDate AS DATE) <=  EOMONTH(EOMONTH(CAST('2019-01-01' AS DATE)))
  GROUP BY Series, ContacNumber, CAST(CDate AS DATE);

WITH CTE_CONTACTS AS
(
  SELECT Series, ContacNumber
  , CDate
  , CDate AS nextCDate
  , CAST(0 AS BIT) AS IsGap
  FROM #tmpContacts

  UNION ALL

  SELECT t1.Series, null
  , DATEADD(day,1,t1.CDate)
  , DATEADD(day,-1,t2.CDate)
  , 1
  FROM #tmpContacts t1
  LEFT JOIN #tmpContacts t2
    ON t2.Series = t1.Series
   AND t2.Rn = t1.Rn + 1
   AND t1.CDate < DATEADD(day,-1,t2.CDate)
)
SELECT c.Series, ContacNumber
, CONCAT(CONVERT(varchar,c.CDate,23), 
        CASE 
        WHEN c.IsGap=1
         AND DATEDIFF(day,c.CDate,c.nextCDate) > 0 
        THEN ' - ' + CONVERT(varchar,c.nextCDate,23) 
        END) AS Cdates
FROM CTE_CONTACTS c
ORDER BY c.Series, c.CDate;
雷克斯试验机的试验


你能试着用一个编辑工具编辑这个问题吗?我正在努力理解这个问题。您是否在询问如何在上述提供的数据中收集指定日期前后2天的数据?我想查找那些在这些日期以及通话前后1或2天从未打过电话的联系人。什么日子?如果联系人在表中,那么他们可能会在该日期打电话。@GordonLinoff,我的意思是说表中缺少的日期,例如,我需要为每个系列生成开始日期和结束日期之间的所有日期,然后找出缺少的日期,如预期结果所示。您可以尝试使用编辑工具编辑问题吗?我正在努力理解这个问题。您是否在询问如何在上述提供的数据中收集指定日期前后2天的数据?我想查找那些在这些日期以及通话前后1或2天从未打过电话的联系人。什么日子?如果联系人在表中,那么他们大概是在那个日期打电话的。@GordonLinoff,我的意思是说表中缺少的日期,例如,我需要为每个系列生成开始日期和结束日期之间的所有日期,然后找出缺少的日期,如预期结果所示。SQL server 2008 r2中是否有“LEAD”功能?@MAK使用我认为可以在mssql 2008 r2中工作的解决方案进行了更新。但是没有一个2008年的版本来测试它。所以试试看。我在你的查询中做了一些更改,看起来几乎完成了,只想得到1/2/3…n个空contactNumber之前/之后的数据。这n个数字将由用户输入以获得前后记录,我们可以输入变量名称@BeforeAfterValue以得到相应的结果。现在我正在获取空值前后的所有值。SQL server 2008 r2中是否有“LEAD”函数?@MAK更新了一个我认为可以在mssql 2008 r2中工作的解决方案。但是没有一个2008年的版本来测试它。所以试试看。我在你的查询中做了一些更改,看起来几乎完成了,只想得到1/2/3…n个空contactNumber之前/之后的数据。这n个数字将由用户输入以获得前后记录,我们可以输入变量名称@BeforeAfterValue以得到相应的结果。现在我得到的是空值前后的所有值。