SQL查询以获取某一天没有值的项目

时间:2014-02-19 16:27:14

标签: sql sql-server sql-server-2012

我有一个MS SQL Server 2012表,其中包含人员的每日报告。每天包含一个人的最多1条记录,日期存储为DateTime,时间部分设置为“00:00:00.000”。示例:'2014-01-30 00:00:00.000'

+-----------+-------------------------+----------------+
| Person id | Date                    | Report content |
+-----------+-------------------------+----------------+
|         1 | 2014-01-29 00:00:00.000 | Account stuff  |
+-----------+-------------------------+----------------+
|         2 | 2014-01-29 00:00:00.000 | Coaching stuff |
+-----------+-------------------------+----------------+
|         2 | 2014-01-30 00:00:00.000 | Still coaching |
+-----------+-------------------------+----------------+

所有人员都存放在一个单独的表格中。

如何从数据库中选择一段时间内缺少记录的人员?即使该人报告了30份报告,但有1份报告丢失,他也应该参与结果。可能会发生,每个人都错过了一个或多个报告日。这就是为什么我无法将人们相互比较的原因。

例如,我想知道谁在1月1日到2月1日之间没有创建他/她的报告。

3 个答案:

答案 0 :(得分:2)

好吧怎么样

DECLARE @StartDate DATETIME = '01 Jan 2014',
        @EndDate DATETIME = '01 Feb 2014'

;WITH Dates AS (
    SELECT @StartDate RunDate
    UNION ALL
    SELECT RunDate + 1
    FROM Dates 
    WHERE RunDate + 1 <= @EndDate
)
, PersonIDs AS (
    SELECT  DISTINCT
            PersonID
    FROM    MyTable
)
, PersonDates AS (
    SELECT  RunDate,
            PersonID
    FROM    Dates,
            PersonIDs
)
SELECT  *
FROM    PersonDates pd LEFT JOIN
        MyTable mt ON pd.RunDate = mt.[Date] AND pd.PersonID = mt.PersonID
WHERE   mt.PersonID IS NULL
OPTION (MAXRECURSION 0)

编辑:

就像简短的观点一样。

使用CTE结构,我使用递归性质来生成日期列表。

然后我检索了一个不同的PersonID s列表(如果你有一个Person表,它也有帮助,或者一个活动列表,或MustReportList等)。

之后我们使用笛卡尔积来生成PersonID的日期列表,以便计算所有日期的所有人。

然后我们将join连接到原始表,并使用IS NULL来确定缺少的条目。

最后,OPTION (MAXRECURSION)是为了确保一旦超过MAX RECURSION LEVEL,我们就不会得到异常(基本上告诉SQL SERVER你知道你在做什么)。

希望有所帮助。

答案 1 :(得分:1)

试试这个:

SELECT DISTINCT PersonID
FROM
[Table] A
WHERE
NOT EXISTS
(
SELECT 1 FROM [Table]
WHERE
    [PersonID] = A.[PersonID]
    AND TRY_CAST([Date] AS DATE) BETWEEN TRY_CAST('January 1, 2014' AS DATE) AND TRY_CAST('February 1, 2014' AS DATE)
)

答案 2 :(得分:0)

Select personid from your_table not in
(
   Select personid from your_table
   Where date between start_date and end_date
 )