SQL Server查询以查找成员注册的年数

时间:2013-04-01 16:54:02

标签: sql sql-server sql-server-2008 sql-server-2005

我有两张桌子:

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循环或者我们如何使用游标来获得上述结果,请帮忙.....

4 个答案:

答案 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

SQL Fiddle Demo

如果您的数据没有这些重叠年份,那么您可以执行以下操作来获得结果:

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

SQL Fiddle Demo

编辑:使用递归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())