Sql server 如何构造SQL语句

Sql server 如何构造SQL语句,sql-server,sql-server-2005,Sql Server,Sql Server 2005,我有一个包含任务列表的表 表名:任务。字段:ID Int,Description nvarchar 任务每天完成,并记录在如下表格中: TableName TasksDone。字段:TaskID Int,TaskDate DateTime 我需要有一个针对某个日期范围运行的查询,该查询显示该范围内每个日期的TasksDone表中不存在未完成的任务 我希望这是有道理的。。。 谢谢您的帮助。如果我正确理解了问题,那么这是非常简单的: SELECT * FROM Tasks WHERE ID NOT

我有一个包含任务列表的表

表名:任务。字段:ID Int,Description nvarchar

任务每天完成,并记录在如下表格中:

TableName TasksDone。字段:TaskID Int,TaskDate DateTime

我需要有一个针对某个日期范围运行的查询,该查询显示该范围内每个日期的TasksDone表中不存在未完成的任务

我希望这是有道理的。。。
谢谢您的帮助。

如果我正确理解了问题,那么这是非常简单的:

SELECT *
FROM Tasks
WHERE ID NOT IN (SELECT TaskID FROM TasksDone WHERE TaskDate BETWEEN x AND y)

将x和y替换为您所处的日期。

我还没有测试过这一点,但看看这是否有帮助:

select ID, TaskDate as A from Tasks,TasksDone
where TaskID not in (select TaskID from TasksDone where TaskDate = A)
GROUP BY TaskDate

你将需要一个数字或日历表,使事情变得简单,或者我们可以模拟一个,如果范围很小。TaskDate是普通日期,还是也有时间组件

攻击的基本计划是:

declare @StartDate datetime
declare @EndDate datetime

/* Set @StartDate and @EndDate to represent the range */

with Digits as (
    select 0 as d union all select 1 union all select 2 union all select 3 union all select 4 union all
    select 5 union all select 6 union all select 7 union all select 8 union all select 9
), Numbers as (
    select (D1.d * 100) + (D2.d * 10) + D3.d as n
    from Digits D1,Digits D2,Digits D3
), TaskDates as (
    select
        t.TaskID,
        DATEADD(day,n.n,@StartDate) as TaskDate
    from
        Tasks t
            inner join
        Numbers n
            on
                DATEADD(day,n.n,@StartDate) <= @EndDate
)
select
    *
from
    TaskDates td1
        left join
    TasksDone td2
        on
            td1.TaskID = td2.TaskID and
            DATEDIFF(day,td1.TaskDate,td2.TaskDate) = 0
where
    td2.TaskID is null
前两个CTE构建一个小数字表,第三个CTE在所需范围内构建一组TaskID和日期。最后一次选择将这些与TasksOne表匹配,然后丢弃找到匹配项的行。如果TasksDone.TaskDate是纯日期无时间组件,@StartDate也没有时间组件,那么您可以放弃DATEDIFF,只使用td1.TaskDate=td2.TaskDate


如果您需要一个较大的范围,可以覆盖~3年,我建议您建立一个适当的数字表或日历表

如果我理解正确,下面的语句应该可以为您提供整个范围内没有每天执行的任务

SQL语句

测试脚本


你好,谢谢你。问题是我需要显示范围内每个日期缺少的任务,所有任务必须每天完成。我需要显示范围内每天缺少的任务。说得通吗?@列文,是的,我说了,不,它没有给我我想要的。它只显示整个范围内未完成的任务,而不是范围内的每个日期。任务表中的所有任务都需要每天完成。我需要显示该范围内每天缺少的所有任务。@rickj:我误解了。SQL Server中没有内置功能来获取某个范围内的所有日期或类似日期。您需要使用数字表或日历表来构建它。太棒了,这看起来太棒了!给我几分钟试试看@rickj-确保你使用的是当前版本-我第一次发布它的时候,有错误的方式添加DATEADD的参数。太棒了!工作是一种享受。谢谢你的解释,帮助我理解到底发生了什么。谢谢Lieven,刚刚注意到你的回答。我也要试试看!没问题。对聚会来说似乎有点轻松,但如果可以的话,请告诉我们结果。@rickj,我把HAVING条款搞砸了。答案已被编辑以修复错误。刚刚测试过,但它没有告诉我我想要什么,如果您查看另一个答案,它会给出该范围内每天未完成的所有任务的日期和任务ID。例如,在范围内的任何时候都不能完成。我应该每天都得到一个结果,这是没有做到的,而不仅仅是一次的范围。无论如何,非常感谢你的时间和努力。@rickj,我又误解了。谢谢你让我们知道。
SELECT  t.*
FROM    @Tasks t
        INNER JOIN (
          SELECT  TaskID
          FROM    @TasksDone td
          WHERE   td.TaskDate BETWEEN @RangeStart AND @RangeEnd        
          GROUP BY
                  td.TaskID
          HAVING  COUNT(TaskID) < CAST(@RangeEnd - @RangeStart AS INTEGER)+1
          UNION ALL
          SELECT  TaskID
          FROM    @TasksDone td
          WHERE   TaskID NOT IN (SELECT TaskID 
                                 FROM   @TasksDone 
                                 WHERE  TaskDate BETWEEN @RangeStart AND @RangeEnd)
        ) td ON td.TaskID = t.ID       
DECLARE @Tasks TABLE (
  ID INTEGER
  , DESCRIPTION NVARCHAR(32)
)

DECLARE @TasksDone TABLE (
  TaskID INTEGER
  , TaskDate DATETIME
)

DECLARE @RangeStart DATETIME
DECLARE @RangeEnd DATETIME

SET @RangeStart = GetDate() - 1
SET @RangeEnd = GetDate() + 1

INSERT INTO @Tasks
          SELECT 1, 'Done Every Day in range.'
UNION ALL SELECT 2, 'Done a few times in range.'
UNION ALL SELECT 3 , 'Not done anytime in range.'

INSERT INTO @TasksDone
          SELECT 1, @RangeStart
UNION ALL SELECT 1, GetDate()
UNION ALL SELECT 1, @RangeEnd
UNION ALL SELECT 2, GetDate()
UNION ALL SELECT 3, GetDate() + 2

SELECT  t.*
FROM    @Tasks t
        INNER JOIN (
          SELECT  TaskID
          FROM    @TasksDone td
          WHERE   td.TaskDate BETWEEN @RangeStart AND @RangeEnd        
          GROUP BY
                  td.TaskID
          HAVING  COUNT(TaskID) < CAST(@RangeEnd - @RangeStart AS INTEGER)+1
          UNION ALL
          SELECT  TaskID
          FROM    @TasksDone td
          WHERE   TaskID NOT IN (SELECT TaskID FROM @TasksDone WHERE TaskDate BETWEEN @RangeStart AND @RangeEnd)
        ) td ON td.TaskID = t.ID