我有一个包含任务列表的表;如何构建SQL语句
表名:任务。字段:(ID Int,描述nvarchar)
任务每天完成并记录在如下表格中;
TableName TasksDone。字段:(的TaskID Int,TaskDate日期时间)
我需要有一个查询运行日期范围,并显示未完成的任务(不存在于TasksDone表)的范围内的每个日期。
我希望这是有道理的... 感谢您的任何帮助。
我有一个包含任务列表的表;如何构建SQL语句
表名:任务。字段:(ID Int,描述nvarchar)
任务每天完成并记录在如下表格中;
TableName TasksDone。字段:(的TaskID Int,TaskDate日期时间)
我需要有一个查询运行日期范围,并显示未完成的任务(不存在于TasksDone表)的范围内的每个日期。
我希望这是有道理的... 感谢您的任何帮助。
您将需要一个数字或日历表让一切变得简单,或者我们可以模拟一个,如果范围小。 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的和日期。最后的选择与TasksDone表相匹配,然后放弃找到匹配的那些行。如果TasksDone.TaskDate是一个普通的日期(没有时间组件),@StartDate也没有时间组件,那么你可以抛弃DATEDIFF并使用td1.TaskDate = td2.TaskDate。
如果你需要一个大的范围(上面可覆盖〜3年),我建议建立一个适当的数字表或日历表
这是相当简单的,如果我理解正确的问题:
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
如果我理解正确的,下面的语句应该得到你,没任务”在整个范围内每天都得到执行。
SQL语句
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
谢谢列文,只是注意到你的答案。我也会试一试! – rickj 2010-09-22 07:11:35
没问题。看起来有点亮的派对,但如果可以的话,让我们知道结果。 – 2010-09-22 07:18:00
@rickj,我搞乱了'HAVING'条款。答案已经过修改以解决错误。 – 2010-09-22 07:25:24
有没有内置的功能在SQL Server中得到的范围内,或类似的所有日期。您需要使用数字表格或日历表格进行构建。 – 2010-09-22 06:43:52