我有一个查询,用于查找表中缺少的日期。
查询为:
;WITH NullGaps AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY ChannelName, ReadingDate) AS ID,
SerialNumber, ReadingDate, ChannelName, uid
FROM
[UriData]
)
SELECT
(DATEDIFF(MINUTE, g1.ReadingDate , g2.ReadingDate) / 15) -1 AS 'MissingCount',
g1.ReadingDate AS 'FromDate', g2.ReadingDate AS 'ToDate'
FROM
NullGaps g1
INNER JOIN
NullGaps g2 ON g1.ID = (g2.ID - 1)
WHERE
DATEADD(MINUTE, 15, g1.ReadingDate) < g2.ReadingDate
输出为:
--------------------------------------------------------------
| MissingCount | FromDate | ToDate |
--------------------------------------------------------------
| 2 | 2018-09-20 14:30:00 | 2018-09-20 15:15:00 |
| 1 | 2018-09-20 15:30:00 | 2018-09-20 16:00:00 |
| 1 | 2018-09-20 20:30:00 | 2018-09-20 21:00:00 |
--------------------------------------------------------------
输出是从FromDate到ToDate(两者都存在)缺少的日期时间数。例如,在输出的第一行(上方)中,我要创建和插入的时间将是'2018-09-20 14:45:00'
和'2018-09-20 15:00:00'
(它们都是15分钟的间隔)
我需要了解如何现在创建新日期并将其插入到现有表中。我可以创建一个日期,但是不能创建两次之间存在多个缺失值的日期。
TIA
答案 0 :(得分:1)
我不理解您的查询来计算缺失值。您的问题没有示例数据或没有逻辑解释。我很确定lag()
会简单得多。
但是考虑到您的查询(或其他查询),扩展数据的一种方法是使用递归CTE:
with missing as (<your query here>)
cte as (
select dateadd(minute, 15, fromdate) as dte, missingcount - 1 as missingcount
from missing
union all
select dateadd(minute, 15, dte), missingcount - 1
from cte
where missingcount > 0
)
select *
from cte;
如果一行中缺少的时间超过100次,则在查询的末尾添加option (maxrecursion 0)
。
答案 1 :(得分:1)
是否还想在日期的开始和结束时查找缺少的日期时间?
然后将其与生成的日期时间进行比较应该是一种有效的方法。
此类日期可以通过递归CTE生成。
然后,您可以将数据连接到递归CTE并选择缺少的数据。
或使用NOT EXISTS
。
例如:
WITH RCTE AS
(
select [SerialNumber], [ChannelName], 0 as Lvl, cast(cast([ReadingDate] as date) as datetime) as ReadingDate
from [UriData]
group by SerialNumber, [ChannelName], cast([ReadingDate] as date)
union all
select [SerialNumber], [ChannelName], Lvl + 1, DATEADD(MINUTE,15,[ReadingDate])
from RCTE
where cast([ReadingDate] as date) = cast(DATEADD(MINUTE,15,[ReadingDate]) as date)
)
SELECT [SerialNumber], [ChannelName], [ReadingDate] AS FromDate
FROM RCTE r
WHERE NOT EXISTS
(
select 1
from [UriData] t
where t.[SerialNumber] = r.[SerialNumber]
and t.[ChannelName] = r.[ChannelName]
and t.[ReadingDate] = r.[ReadingDate]
);
可以找到测试here
这是另一个使用不同approuch的查询:
WITH CTE AS
(
SELECT SerialNumber, ChannelName, ReadingDate,
LAG(ReadingDate) OVER (PARTITION BY SerialNumber, ChannelName ORDER BY ReadingDate) AS prevReadingDate
FROM [UriData]
)
, RCTE AS
(
select SerialNumber, ChannelName, 0 as Lvl,
prevReadingDate AS ReadingDate,
prevReadingDate AS MinReadingDate,
ReadingDate AS MaxReadingDate
from CTE
where DATEDIFF(MINUTE, prevReadingDate, ReadingDate) > 15
union all
select SerialNumber, ChannelName, Lvl + 1,
DATEADD(MINUTE,15,ReadingDate),
MinReadingDate,
MaxReadingDate
from RCTE
where ReadingDate < DATEADD(MINUTE,-15,MaxReadingDate)
)
select SerialNumber, ChannelName,
ReadingDate AS FromDate,
DATEADD(MINUTE,15,ReadingDate) AS ToDate,
dense_rank() over (partition by SerialNumber, ChannelName order by MinReadingDate) as GapRank,
(DATEDIFF(MINUTE, MinReadingDate, MaxReadingDate) / 15) AS TotalMissingQuarterGaps
from RCTE
where Lvl > 0 AND MinReadingDate < MaxReadingDate
ORDER BY SerialNumber, ChannelName, MinReadingDate;
您可以测试一个here
答案 2 :(得分:0)
根据与我分享的信息,我做了以下我所需的事情。
第一部分是通过查找日期和日期之间缺少日期的日期来查找缺少的日期范围,然后将它们插入表中进行审核,但是它将保留我要查找的日期:
;WITH NullGaps AS(
SELECT ROW_NUMBER() OVER (ORDER BY ChannelName, ReadingDate) AS ID,SerialNumber, ReadingDate, ChannelName, uid
FROM [Staging].[UriData]
)
INSERT INTO [Staging].[MissingDates]
SELECT (DATEDIFF(MINUTE, g1.ReadingDate , g2.ReadingDate) / 15) -1 AS 'MissingCount',
g1.ChannelName,
g1.SerialNumber,
g1.ReadingDate AS FromDate,
g2.ReadingDate AS ToDate
FROM NullGaps g1
INNER JOIN NullGaps g2
ON g1.ID = (g2.ID - 1)
WHERE DATEADD(MINUTE, 15, g1.ReadingDate) < g2.ReadingDate
AND g1.ChannelName IN (SELECT ChannelName FROM staging.ActiveChannels)
AND NOT EXISTS(
SELECT 1 FROM [Staging].[MissingDates] m
WHERE m.Channel = g1.ChannelName
AND m.Serial = g1.SerialNumber
AND m.FromDate = g1.ReadingDate
AND m.ToDate = g2.ReadingDate
)
现在有了要查找的范围,我现在可以创建缺失的日期并将其插入保存真实数据的表中。
;WITH MissingDateTime AS(
SELECT DATEADD(MINUTE, 15, FromDate) AS dte, MissingCount -1 AS MissingCount, Serial, Channel
FROM [Staging].[MissingDates]
UNION ALL
SELECT DATEADD(MINUTE, 15, dte), MissingCount - 1, Serial, Channel
FROM MissingDateTime
WHERE MissingCount > 0
) -- END CTE
INSERT INTO [Staging].[UriData]
SELECT NEWID(), Serial, Channel, '999', '0', dte, CURRENT_TIMESTAMP, 0,1,0 FROM MissingDateTime m
WHERE NOT EXISTS(
SELECT 1 FROM [Staging].[UriData] u
WHERE u.ChannelName = m.Channel
AND u.SerialNumber = m.Serial
AND u.ReadingDate = m.dte
) -- END SELECT
我确信您可以对此进行改进。此解决方案仅查找缺少的日期,并允许我仅用缺少的日期回填数据表。如果以后需要将其他设备用于不同的间隔,我也可以更改间隔。我将查询放在两个分散的SPROC中,以便可以同时控制两个方面:一个用于审计,一个用于回填。