我希望找到解决这个问题的方法。我有一个名为LogEntry的表,用于存储多个办公室使用的信息,他们必须在任何一天记录进入办公室的任何访问者。如果没有访客进入,他们仍然需要登录"没有访客"为了这一天。如何运行一个查询,提取办公室无法创建的所有日期,即使是“没有访客”#34;登录?
我查看了this question(以及内部链接的文章),但即使调整了该查询,我也只能为办公室遗漏的日期创建一个空白行输入日期,而不是指定未创建条目的实际办公室。有没有办法做我想做的事情?
declare @temp table (
CDate datetime,
loc_id varchar(50)
)
insert into @temp SELECT DISTINCT entryDate, locationID FROM LogEntry WHERE entryDate >= '05/01/2017' AND entryDate <= '07-31-2017'
;with d(date) as (
select cast('05/01/2017' as datetime)
union all
select date+1
from d
where date < '07/31/2017'
)
select DISTINCT t.loc_id, CONVERT(date, d.date)
FROM d LEFT OUTER JOIN @temp t ON d.date = t.CDate
GROUP BY t.loc_id, d.date
ORDER BY t.loc_id
正如我所说,这个查询返回了日期范围内的日期列表,以及在该日期提交条目的所有位置,但我想找到一种方法来提取相反的信息:如果是office(由locationID指定)没有在给定的一天提交条目,只返回那些locationID和它们错过的日期。
Sample data
EntryID | locationID | entryDate
=================================
1 1 07-01-2017
2 1 07-02-2017
3 2 07-02-2017
4 1 07-04-2017
Expected Result (for date range of 07-01 to 07-04)
locationID | missedEntryDate
============================
1 07-03-2017
2 07-01-2017
2 07-03-2017
2 07-04-2017
答案 0 :(得分:2)
您的第一步很好,您创建了所有日期的列表,但您还需要所有位置的列表。然后创建一个交叉连接以包含所有组合,然后执行var d = '';
以找出缺少的内容。
left join
答案 1 :(得分:0)
如果您的数据集不是太大,可以试试这个:
select t.loc_id, CONVERT(date, d.date)
FROM d
-- Cross join dates to all available locs
CROSS JOIN (SELECT DISTINCT loc_id FROM @temp ) AS Locs
LEFT JOIN
( SELECT loc_id, t.CDate
FROM @temp
GROUP BY loc_id, d.date ) AS t ON d.date = t.CDate AND Locs.loc_id = t.loc_id
ORDER BY Locs.loc_id
这应该快一点:
;WITH cte AS (
SELECT a.LocID, RangeStart.CDate, ( CASE WHEN Input.LocID IS NULL THEN 1 ELSE 0 END ) AS IsMissing
FROM ( SELECT DISTINCT LocID FROM #temp ) AS a
CROSS JOIN ( SELECT CONVERT( DATETIME, '2017-05-01' ) AS CDate ) AS RangeStart
LEFT JOIN
( SELECT LocID, MIN( CDate ) AS CDate
FROM #temp
WHERE CDate = '2017-05-01'
GROUP BY LocID ) AS Input ON a.LocID = Input.LocID AND RangeStart.CDate = Input.CDate
UNION ALL
SELECT a.LocID, a.CDate + 1 AS CDate,
ISNULL( ItExists, 0 ) AS IsMissing
FROM cte AS a
OUTER APPLY( SELECT LocID, 1 AS ItExists FROM #temp AS b WHERE a.LocID = b.LocID AND a.CDate + 1 = b.CDate ) AS c
WHERE a.CDate < '2017-07-01'
)
SELECT * FROM cte OPTION( MAXRECURSION 0 )
您还可以添加索引:
CREATE INDEX IX_tmp_LocID_CDate ON #temp( LocID, CDate )
第二个查询的示例数据集:
CREATE TABLE #temp( LocID VARCHAR( 50 ), CDate DATETIME )
INSERT INTO #temp
VALUES
( '1', '2017-05-01' ), ( '1', '2017-05-02' ), ( '1', '2017-05-03' ), ( '1', '2017-05-04' ), ( '1', '2017-05-05' ),
( '2', '2017-05-01' ), ( '2', '2017-05-02' ), ( '2', '2017-05-03' ), ( '2', '2017-05-04' ), ( '2', '2017-05-05' )
;WITH d AS (
SELECT CAST( '05/01/2017' AS DATETIME ) AS date
UNION ALL
SELECT date + 2
FROM d
WHERE date < '2018-07-31'
)
INSERT INTO #temp
SELECT LocID, d.date
FROM ( SELECT DISTINCT LocID FROM #temp ) AS a
CROSS JOIN d
OPTION( MAXRECURSION 0 )