我在数据库中有TableA
,类似于以下内容:
Id | Status | Start | End
1 | Illness | 2013-04-02 | 2013-04-23
2 | Illness | 2013-05-05 | 2014-01-01
3 | Vacation | 2014-02-01 | 2014-03-01
4 | Illness | 2014-03-08 | 2014-03-09
5 | Vacation | 2014-05-05 | NULL
想象一下,它跟踪特定用户"离开"天。给出以下输入:
SomeEndDate
(日期),NumDays
(整数)我希望找到距离SomeStartDate
Numdays
({1}}非疾病日的EndDate
(日期)。换句话说,假设我获得SomeEndDate
价值' 2014-03-10'和NumDays
值为60;匹配的SomeStartDate将是:
因此,在60个非疾病日,我们得到了SomeStartDate
' 2013-05-03'。有没有简单的方法在SQL中实现这一点?我想我可以每天循环,检查它是否属于其中一个疾病范围,如果没有,则增加一个计数器(在计数器= @numdays之后退出循环)......但这似乎非常低效。感谢任何帮助。
答案 0 :(得分:1)
制作一张日历表,其中列出了您将关注的所有日期。
SELECT MIN([date])
FROM (
SELECT TOP(@NumDays) [date]
FROM Calendar c
WHERE c.Date < @SomeEndDate
AND NOT EXISTS (
SELECT 1
FROM TableA a
WHERE c.Date BETWEEN a.Start AND a.END
AND Status = 'Illness'
)
ORDER BY c.Date
) t
Calendar表方法还可以轻松排除假期,周末等。
答案 1 :(得分:0)
SQL Server 2012:
试试这个解决方案:
DECLARE @NumDays INT = 70, @SomeEndDate DATE = '2014-03-10';
SELECT
[RangeStop],
CASE
WHEN RunningTotal_NumOfDays <= @NumDays THEN [RangeStart]
WHEN RunningTotal_NumOfDays - Current_NumOfDays <= @NumDays THEN DATEADD(DAY, -(@NumDays - (RunningTotal_NumOfDays - Current_NumOfDays))+1, [RangeStop])
END AS [RangeStart]
FROM (
SELECT
y.*,
DATEDIFF(DAY, y.RangeStart, y.RangeStop) AS Current_NumOfDays,
SUM( DATEDIFF(DAY, y.RangeStart, y.RangeStop) ) OVER(ORDER BY y.RangeStart DESC) AS RunningTotal_NumOfDays
FROM (
SELECT LEAD(x.[End]) OVER(ORDER BY x.[End] DESC) AS RangeStart, -- It's previous date because of "ORDER BY x.[End] DESC"
x.[Start] AS RangeStop
FROM (
SELECT @SomeEndDate AS [Start], '9999-12-31' AS [End]
UNION ALL
SELECT x.[Start], x.[End]
FROM @MyTable AS x
WHERE x.[Status] = 'Illness'
AND x.[End] <= @SomeEndDate
) x
) y
) z
WHERE RunningTotal_NumOfDays - Current_NumOfDays <= @NumDays;
/*
Output:
RangeStop RangeStart
---------- ----------
2014-03-10 2014-03-09
2014-03-08 2014-01-01
2013-05-05 2013-05-03
*/
注意#1:LEAD(End)
将返回上一个结束日期(之前因为ORDER BY End DESC)
注意#2:DATEDIFF(DAY, RangeStart, RangeStop)
计算num。当前开始(别名x.RangeStop
)和&#34;之前&#34;之间的天数结束(别名x.RangeStar
)=&gt; Current_NumOfDays
注意#3:SUM( Current_NumOfDays )
计算一个总计:1 + 66 +(3)
注意#4:我使用了@NumOfDays = 70
(不是60
)