年が重複する可能性があると仮定すると (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