用于标识特定日期的缺失数据的SQL Server查询

时间:2015-05-25 06:37:09

标签: sql-server sql-server-2008

我有一个表,其中包含需要在一天中定期检查的数据,以确保正确更新。

每一天都应该插入此表,如下所示:

           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。

我怎样才能编写一个查询,该查询将返回缺少数据的日期以及缺少数据的单位?

2 个答案:

答案 0 :(得分:5)

您可以使用Tally Table生成DateUnit的所有组合。获得所有组合后,您可以使用NOT EXISTS来获取缺失的数据。

SQL Fiddle

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 AUnit 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

See fiddle here