我有两张桌子:
表tbmembers
id name
----------
1 abc
2 def
3 ghi
表tbmemberenrollment
id memberid(foreign key) startyear endyear
--------------------------------------------------
1 1 2007 2009
2 1 2011 2012
3 1 2013 2017
在tbmemberenrollment
表中,我想计算会员注册到当年的年数,在这种情况下,结果将是6年(2007年,2008年,2009年,2011年,2012年,2013年) )
我想通过SQL查询计算上面的结果,我不知道如何在SQL Server中使用for循环或者我们如何使用游标来获得上述结果,请帮忙.....
答案 0 :(得分:2)
假设您的年份可能重叠(2007-2008和2008-2009),我看到的最佳选择是创建一个年份查找表并对其进行查询,如下所示:
SELECT m.id, m.name, COUNT(DISTINCT y.yearfield) YearCount
FROM tblmembers m
CROSS JOIN YearLookup Y
INNER JOIN tbmemberenrollment me
ON m.id = me.memberid
AND YEAR(y.yearfield) >= YEAR(me.startyear)
AND YEAR(y.yearfield) <= YEAR(me.endyear)
AND YEAR(Y.yearField) <= YEAR(GetDate())
GROUP BY m.id, m.name
如果您的数据没有这些重叠年份,那么您可以执行以下操作来获得结果:
SELECT m.id, m.name,
SUM(
CASE
WHEN YEAR(me.endyear) > YEAR(getDate())
THEN YEAR(getDate())
ELSE YEAR(me.endyear)
END - YEAR(me.startyear) + 1
) totYears
FROM tblmembers m
LEFT JOIN tbmemberenrollment me on m.id = me.memberid
WHERE YEAR(me.startyear) <= YEAR(getDate())
GROUP BY m.id, m.name
编辑:使用递归CTE与查找表
虽然我仍然建议使用查找表,但有时候这不是一个可行的选择。在这些情况下,您可以使用递归CTE完成相同的操作。
WITH years AS (
SELECT MAX(endyear) maxyear, MIN(startyear) minyear
FROM tbmemberenrollment
),
RecursiveCTE AS (
SELECT minyear yearfield
FROM years
UNION ALL
SELECT DATEADD(year, 1, yearfield)
FROM RecursiveCTE R
JOIN years T
ON R.yearfield < T.maxyear
)
SELECT m.id, m.name, COUNT(DISTINCT y.yearfield) YearCount
FROM tblmembers m
CROSS JOIN RecursiveCTE Y
INNER JOIN tbmemberenrollment me
ON m.id = me.memberid
AND YEAR(y.yearfield) >= YEAR(me.startyear)
AND YEAR(y.yearfield) <= YEAR(me.endyear)
AND YEAR(Y.yearField) <= YEAR(GetDate())
GROUP BY m.id, m.name
答案 1 :(得分:0)
怎么样?:
SELECT Count(DISTINCT c.yr)
FROM (SELECT a.startyear AS yr
FROM tbmemberenrollment a
UNION
SELECT b.endyear AS yr
FROM tbmemberenrollment b) AS c
答案 2 :(得分:0)
这是CTE查询的一个很好的条件。
;with memberEnrollment_CTE(memberid, Eyear, Startyear, Endyear)
as
(
SELECT memberid, startyear as EYear, startyear, endyear
from dbo.tbmemberenrollment
union all
select memberid, Eyear+1, Startyear, Endyear
from memberEnrollment_CTE
where endyear>yyear
)
select distinct memberid, Eyear as EnrolledYear from memberEnrollment_CTE where
Eyear<= YEAR(GETDATE())
这甚至适用于重叠登记年份。并且应该给你所有年份,所以你可以对此运行count()查询或与成员表连接。
答案 3 :(得分:0)
如果您的年份不重叠,您可以进行汇总:
select tm.name,
sum(case when endyear <= year(getdate()) then endyear - startyear + 1
else year(getdate()) - startyear + 1
end) as EnrollmentYears
from tmembers tm join
tbmemberenrollment tme
on tm.id = tme.memberid
where startyear <= year(getdate())