3

次のサンプルデータを使用して、SQLServerで再帰CTEを実行しようとしています

Class        Student
------       ------
English      Sally   <- Sally is what were searching for
English      Peter   <- Peter's on same Class as Sally
Swedish      Peter   <- Found because Peter's on this class
Dutch        Peter   <- Found because Peter's on this class
Finnish      Harry   <- Not found, no relation to class or student
Swedish      Tim     <- Found because Peter's on Swedish class
Spanish      Lauren  <- Not found, no relation to class or student
Spanish      Colin   <- Not found, no relation to class or student

したがって、パラメータとして「Sally」を指定するCTEが必要です。これにより、Sallyに関連するすべての異なるクラス、Sallyが属するクラスに関連するすべての学生、同じクラスの学生に関連するすべてのクラスが検出されます。サリーなど、行がなくなるまで続けます。

しかし、結合の書き方がわかりません。これは私が試したものですが、惨めに失敗しました。

WITH myCTE (Class, Student) AS
(
    SELECT Class, Student FROM TABLE1 WHERE TABLE1.Student= 'Sally'
    UNION ALL
    SELECT t.Class, t.Student FROM TABLE1 t
    JOIN myCTE t2 ON t2.Class = t.Class
)
SELECT * FROM myCTE
4

1 に答える 1

2

最初の問題は、無限の再帰があることです。サリーはピーターと英語を取り、サリーは英語を取り、ピーターは英語を取ります...

それを整理したら、再帰CTEに追加のクエリが必要になります。現在Class、同じクラスの他の生徒を取得するために参加していますStudentが、生徒のために他のクラスを取得するためにも参加する必要があります。

このようなものが機能するはずです:

WITH cteSource As
(
   SELECT
      Class,
      Student,
      -- Create a unique ID for each record:
      ROW_NUMBER() OVER (ORDER BY Student, Class) As ID
   FROM
      TABLE1
),
cteRecursive (Class, Student, IDPath) As
(
   SELECT
      Class,
      Student,
      -- Used to exclude records we've already visited:
      Convert(varchar(max), '/' + Convert(varchar(10), ID) + '/')
   FROM
      cteSource
   WHERE
      Student = 'Sally'

   UNION ALL

   -- Students in the same class:
   SELECT
      T.Class,
      T.Student,
      R.IDPath + Convert(varchar(10), T.ID) + '/'
   FROM
      cteSource As T
      INNER JOIN cteRecursive As R
      ON T.Class = R.Class
   WHERE
      CharIndex('/' + Convert(varchar(10), t.ID) + '/', R.IDPath) = 0

   UNION ALL

   -- Other classes for the students:
   SELECT
      T.Class,
      T.Student,
      R.IDPath + Convert(varchar(10), T.ID) + '/'
   FROM
      cteSource As T
      INNER JOIN cteRecursive As R
      ON T.Student = R.Student
   WHERE
      CharIndex('/' + Convert(varchar(10), t.ID) + '/', R.IDPath) = 0
)
SELECT
   Class,
   Student,
   IDPath
FROM
   cteRecursive
;

テストデータを使用すると、次の結果が得られます。

English   Sally   /7/
English   Peter   /7/5/
Dutch     Peter   /7/5/4/
Swedish   Peter   /7/5/6/
Swedish   Tim     /7/5/6/8/
Dutch     Peter   /7/5/6/4/
Swedish   Peter   /7/5/4/6/
Swedish   Tim     /7/5/4/6/8/

SQL 2008以降を使用している場合は、を作成するとパフォーマンスが向上する可能性がありますがIDPathHierarchyID実際のデータでテストする必要があります。

編集
最終選択を次のように変更する必要がある場合があります。

SELECT DISTINCT
   Class,
   Student
FROM
   cteRecursive

同じレコードへのパスが複数ある場合に対処します。たとえば、「Dutch / Peter」、「Swedish / Peter」、「Swedish/Tim」はすべて2回表示されます。

于 2012-11-29T13:34:25.280 に答える