Sql 查找缺少的联系日期详细信息
我有下表和联系人详细信息: 表:TBL合同 样本数据: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
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以得到相应的结果。现在我得到的是空值前后的所有值。