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

これは、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

How about?:

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 に答える