3

我有 2 张桌子:

桌子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

4 回答 4

2

假设您的年份可能重叠(2007-2008 年,然后是 2008-2009 年),我看到的最佳选择是创建一个 Years 查找表并对其进行查询,如下所示:

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 小提琴演示

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

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 小提琴演示

编辑:使用递归 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
于 2013-04-01T17:18:57.080 回答
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 
于 2013-04-01T17:12:53.903 回答
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() 查询或加入成员表。

于 2013-04-01T17:46:14.947 回答
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())
于 2013-04-01T18:07:18.463 回答