我有一个表,其中包含需要在一天中定期检查的数据,以确保正确更新。
每一天都应该插入此表,如下所示:
CORRECT
| Date | Unit | Paid |
| 1/1/12 | Unit A | YES |
| 1/1/12 | Unit B | YES |
| 1/2/12 | Unit A | NO |
| 1/2/12 | Unit B | NO |
因此,对于单元A和单元B,每天应该有数据。但是,有时我的程序没有正确返回数据,我最终会丢失某些日期的数据或接收某个日期的数据,但仅限于一个单位:
INCORRECT
| Date | Unit | Paid |
| 1/1/12 | Unit A | YES |
| 1/3/12 | Unit A | NO |
| 1/3/12 | Unit B | NO |
单元B的数据缺失1/1/12。单元A和B的数据缺失1/2/12。
我怎样才能编写一个查询,该查询将返回缺少数据的日期以及缺少数据的单位?
答案 0 :(得分:5)
您可以使用Tally Table生成Date
和Unit
的所有组合。获得所有组合后,您可以使用NOT EXISTS
来获取缺失的数据。
DECLARE @minDate AS DATE
DECLARE @maxDate AS DATE
SELECT
@minDate = MIN([Date]),
@maxDate = MAX([Date])
FROM TestData
;WITH E1(N) AS(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b),
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b),
Tally(N) AS(
SELECT TOP(DATEDIFF(DAY, @minDate, @maxDate) + 1)
ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E4
),
CteDatesAndUnits([Date], Unit) AS(
SELECT
DATEADD(DAY, t.N - 1, @minDate),
u.Unit
FROM Tally t
CROSS JOIN (
SELECT DISTINCT Unit FROM TestData
)u
)
SELECT *
FROM CteDatesAndUnits c
WHERE NOT EXISTS(
SELECT *
FROM TestData
WHERE
[Date] = c.[Date]
AND Unit = c.Unit
)
<强>结果强>
| Date | Unit |
|------------|--------|
| 2012-01-01 | Unit B |
| 2012-01-02 | Unit A |
| 2012-01-02 | Unit B |
由于Unit
始终为Unit A
和Unit B
,您可以替换此行:
SELECT DISTINCT Unit FROM TestData
用这个:
SELECT 'Unit A' AS Unit UNION ALL SELECT 'Unit B'
答案 1 :(得分:1)
那么,在这种情况下,我可能会做这样的事情:
DECLARE @FromDate date, @ToDate date
-- Or you can use Max and Min date from your table
SELECT @FromDate = '2015-01-01',
@ToDate = '2015-01-07'
-- use a recursive cte to get all the dates between from date and to date
;With CTE AS (
SELECT @FromDate As TheDate
UNION ALL
SELECT DateAdd(Day, 1, TheDate)
FROM CTE
WHERE TheDate < @ToDate
)
-- select dates where all the units are missing
SELECT TheDate, 'All' as Missing_Units
FROM CTE
LEFT JOIN YourTable ON(YourTable.Date = CTE.TheDate)
WHERE Unit IS NULL
UNION ALL
-- select dates where 'Unit B' is missing
SELECT T1.Date, 'Unit B' as Missing_Units
FROM YourTable T1
LEFT JOIN (
SELECT Date, Unit
FROM YourTable
WHERE Unit = 'Unit B'
) T2 ON(T1.Date = T2.Date)
WHERE T2.Unit IS NULL
UNION ALL
-- select dates where 'Unit A' is missing
SELECT T1.Date, 'Unit A' as Missing_Units
FROM YourTable T1
LEFT JOIN (
SELECT Date, Unit
FROM YourTable
WHERE Unit = 'Unit A'
) T2 ON(T1.Date = T2.Date)
WHERE T2.Unit IS NULL