我有一张表dbo.MyDates
:
date
--------
'08/28/2012'
'01/10/2013'
'02/05/2013'
和表dbo.People
:
id name dateRangeStart dateRangeEnd
--- ------ -------------- ------------
100 Mike '08/01/2012' '11/15/2012'
101 John '08/01/2012' '02/01/2013'
102 Claire '12/01/2012 '03/15/2013'
103 Mary '03/01/2013' '05/01/2013'
我要做的是检查第1-3行中的每个日期是否在特定日期范围内,然后总计在该范围内的日期数:
id name totalDaysWithinRange
--- ------ --------------------
100 Mike 1
101 John 2
102 Claire 2
103 Mary 0
这样我就可以在简单的数学计算中使用totalDaysWithinRange
。我知道如何使用来自其他语言(如Java和PHP)的while循环,但根据我的研究,似乎在T-SQL中使用递归CTE会更好。我过去曾使用过CTE,所以我知道它们是如何工作的,但我以前从未使用过递归CTE。这就是我想出的:
WITH cte AS
(
SELECT
p.id AS personID,
p.name AS personName,
p.dateRangeStart AS drs,
p.dateRangeEnd AS dre,
d.date AS checkedDate
FROM dbo.MyDates AS d, dbo.People AS p
WHERE d.date BETWEEN p.dateRangeStart AND p.dateRangeEnd
UNION ALL
SELECT
cte.personID,
cte.personName,
cte.drs,
cte.dre,
cte.checkedDAte
FROM cte
INNER JOIN dbo.MyDates AS d
ON d.date = cte.checkedDate
)
SELECT
p.id
p.name,
COUNT(cte.personID)
FROM cte AS c
INNER JOIN dbo.Person AS p ON p.id = c.personID)
;
我无法弄清楚如何计算总和,以便我可以在SELECT from cte
中使用它们。谢谢你的帮助。
答案 0 :(得分:0)
SELECT P.id, P.name, ISNULL(A.totalDaysWithinRange, 0) totalDaysWithinRange
FROM PEOPLE P
LEFT JOIN (SELECT P.id, P.name, COUNT(*) totalDaysWithinRange
FROM PEOPLE P
JOIN MyDates D ON P.dateRangeStart < D.date
AND D.date < P.dateRangeEnd
GROUP BY P.id, P.name) A ON A.ID = P.ID
SQLFIDDLE:http://sqlfiddle.com/#!3/073d9/14/0
CTE似乎在stackoverflow上出现在很多答案中,但很少用于CTE的目的。在这种情况下,我没有看到使用CTE的理由。
答案 1 :(得分:0)
这应该有效:
;with cte as
(
select id, count(*) as dayCount
from People p
join MyDates d on d.[Date] between p.dateRangeStart and p.dateRangeEnd
group by id
)
select p.id, p.name, isnull(cte.dayCount,0) as totalDaysWithinRange
from cte
right join People p on p.id = cte.id
order by p.id