我有一个包含任务列表的表格;
TableName:任务。字段:(ID Int,Description nvarchar)
任务每天完成,并记录在如下表格中;
TableName TasksDone。字段:(TaskID Int,TaskDate DateTime)
我需要有一个运行日期范围的查询,并显示范围内每个日期未完成的任务(在TasksDone表中不存在)。
我希望这是有道理的...... 谢谢你的帮助。
答案 0 :(得分:2)
如果我正确理解问题,这是相当直接的:
SELECT *
FROM Tasks
WHERE ID NOT IN (SELECT TaskID FROM TasksDone WHERE TaskDate BETWEEN x AND y)
将x
和y
替换为您之后的日期。
答案 1 :(得分:2)
您需要一个数字或日历表来简化操作,或者如果范围很小,我们可以模拟一个。 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和Dates。最终选择将这些与TasksDone表相匹配,然后丢弃找到匹配项的那些行。如果TasksDone.TaskDate是一个普通日期(没有时间组件)而且@StartDate也没有时间组件,那么你可以抛弃DATEDIFF并使用td1.TaskDate = td2.TaskDate。
如果你需要大范围(以上可以覆盖〜3年),我建议建立一个合适的号码表或日历表
答案 2 :(得分:0)
我没有对此进行测试,但看看这是否有帮助:
select ID, TaskDate as A from Tasks,TasksDone
where TaskID not in (select TaskID from TasksDone where TaskDate = A)
GROUP BY TaskDate
答案 3 :(得分:0)
如果我理解正确,下面的陈述应该会让你在整个范围内每天都没有执行任务。
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