SQL SERVER 2005バージョン以上のCTE再帰クエリの実装
24498 ワード
今日は基本的にSQL Serverの再帰クエリの実現方法を明らかにして、So、先に記録します.しかし、個人的にはSQL Serverの再帰クエリは、Oracleの再帰クエリよりも理解しにくいと思います.
SQL Server 2005からは、ツリーまたは階層のデータをクエリーするのに役立つCTEを直接使用して再帰クエリーをサポートできます.CTEは共通テーブル式であり、適切ではありませんが、一時的に命名された結果の集合と見なすことができます.
まず、メニューの階層を表すMENUという名前のサンプルテーブルを作成します.
表示されるメニュー階層は次のとおりです.
例:
lmenuという名前のCTEを定義し、その後、lmenuを直接使用してクエリーできます.たとえば、次のようにします.
CTEを定義するクエリー文でCTEテーブル自体を直接参照すると、再帰クエリーが形成されます.もちろん、再帰クエリーには独自の特殊な構造があります.次のSQLは、再帰クエリーによって各メニューの階層の深さを取得します.
結果:
クエリ定義文は、2つのクエリ文で構成されていることに注意してください.
配置メンバーと呼ばれ、SQL Serverはこの文で再帰を続行するかどうかを判断します.
再帰メンバーと呼ばれ、from句でCTEオブジェクト自体が参照されていることを特徴とします.
再帰CTEはいくつかの制限条件(MSDNから引用)を有する.
少なくとも1つのロケーションポイントメンバーと1つの再帰メンバーがあります.もちろん、複数のロケーションポイントメンバーと再帰メンバーを定義できますが、すべてのロケーションポイントメンバーは再帰メンバーの前にある必要があります.
位置決めポイントメンバー間ではUNIOALL、UNION、INTERSECT、EXCEPT集合演算子を使用する必要があり、最後の位置決めポイントメンバーと再帰メンバー間ではUNIOALLを使用する必要があり、再帰メンバー間でもUNIOALL接続を使用する必要があります
位置決めポイントメンバーと再帰メンバーのフィールド数とタイプは完全に一致する必要があります.
再帰メンバーのFROM句はCTEオブジェクトを一度しか参照できません
再帰メンバーでは、次の項目は許可されていません.
CTE再帰クエリの実行方法:
再帰的な終了は、ポイント・メンバーの位置決めに依存し、それが理解されると、再帰クエリの実行方法も理解されます.
上記の例の実行手順を見てみましょう.
この文は再帰クエリに入ります
最外層の文として、再帰的な第1層は、menuテーブルでクエリされたレコードの順序が次のようになると仮定して、MENUテーブルのレコードに基づいてループする必要があることは明らかです.
1番目のレコード:
まず、再帰に入るかどうかを判断します.ファイルは位置決めポイントメンバー結果セットに含まれており、再帰条件に合致しないため、再帰に入らず、直接位置決めポイントメンバーセットからレコードを返します.
第二条記録:
すなわちNAME='新規'であり、位置決めポイントのメンバー結果セットに記録がなく、再帰に入ります.
現在のローの値を再帰メンバーに持ち込むには、次の手順に従います.
再帰の関連条件はa.senior=b.nameであるため、b.name='ファイル'は、この条件で下位再帰に入ります.これは実際には最初のレコードの場合です.name='ファイル'は位置決め点の条件に合致するため、再帰は終了します.lmenu再帰メンバーをサブクエリで置き換えると、2番目のレコードのクエリ文は実際には次のようになります.
name senior level----------------------------------------------------------------新規ファイル1
第三条記録:
NAME='現在の接続クエリーを使用する'は、同じように位置決めポイントの条件を満たしていないため、再帰的になります.
同様に、現在のレコード条件を代入し、下位再帰b.name='新規'であり、'新規'は位置決め点条件に合致しないため、再帰を継続し、lmenu bはサブクエリを表す.
上記の文に置き換えると、d.name='ファイル'は、再帰を継続する必要があるかどうかを再判断し、'ファイル'は再帰を終了する条件に合致するため、再帰を終了します.
サブクエリを使用して、3番目のレコードの再帰プロセスを次のように表します.
name senior level
--------------------------------------------------------- -----------
現在の接続クエリーを使用して新規2を作成
第4条記録は第3条記録の再帰階層と全く同じである.
SQL Server 2005からは、ツリーまたは階層のデータをクエリーするのに役立つCTEを直接使用して再帰クエリーをサポートできます.CTEは共通テーブル式であり、適切ではありませんが、一時的に命名された結果の集合と見なすことができます.
まず、メニューの階層を表すMENUという名前のサンプルテーブルを作成します.
- CREATE TABLE MENU
- (
- name nvarchar(50) NOT NULL PRIMARY KEY,
- senior nvarchar(50) NULL
- );
-
- INSERT INTO MENU values
- (' ',NULL),
- (' ',' '),
- (' ',' '),
- (' ',' ');
表示されるメニュー階層は次のとおりです.
-
-
-
-
-
- OK, CTE :
- WITH CTE ( )
- AS
- (
-
- )
例:
- WITH lmenu(name,senior)
- as
- (
- SELECT name,senior from menu
- )
lmenuという名前のCTEを定義し、その後、lmenuを直接使用してクエリーできます.たとえば、次のようにします.
- SELECT * FROM lmenu
CTEを定義するクエリー文でCTEテーブル自体を直接参照すると、再帰クエリーが形成されます.もちろん、再帰クエリーには独自の特殊な構造があります.次のSQLは、再帰クエリーによって各メニューの階層の深さを取得します.
- WITH lmenu(name,senior,level) as
- (
- SELECT NAME,SENIOR,0 level FROM MENU WHERE SENIOR IS NULL
- UNION ALL
- SELECT A.NAME,A.SENIOR,b.level+1 FROM MENU A,lmenu b
- where a.senior = b.name
- )
-
- SELECT * from lmenu
結果:
- name senior level
- ----------------------------------- -----------
- NULL 0
- 1
- 2
- 2
クエリ定義文は、2つのクエリ文で構成されていることに注意してください.
- SELECT NAME,SENIOR,0 level FROM MENU WHERE SENIOR IS NULL
配置メンバーと呼ばれ、SQL Serverはこの文で再帰を続行するかどうかを判断します.
- SELECT A.NAME,A.SENIOR,b.level+1 FROM MENU A,lmenu b
- where a.senior = b.name
再帰メンバーと呼ばれ、from句でCTEオブジェクト自体が参照されていることを特徴とします.
再帰CTEはいくつかの制限条件(MSDNから引用)を有する.
少なくとも1つのロケーションポイントメンバーと1つの再帰メンバーがあります.もちろん、複数のロケーションポイントメンバーと再帰メンバーを定義できますが、すべてのロケーションポイントメンバーは再帰メンバーの前にある必要があります.
位置決めポイントメンバー間ではUNIOALL、UNION、INTERSECT、EXCEPT集合演算子を使用する必要があり、最後の位置決めポイントメンバーと再帰メンバー間ではUNIOALLを使用する必要があり、再帰メンバー間でもUNIOALL接続を使用する必要があります
位置決めポイントメンバーと再帰メンバーのフィールド数とタイプは完全に一致する必要があります.
再帰メンバーのFROM句はCTEオブジェクトを一度しか参照できません
再帰メンバーでは、次の項目は許可されていません.
- SELECT DISTINCT
- GROUP BY
- HAVING
-
- TOP
- LEFT、RIGHT、OUTER JOIN( INNER JOIN)
-
CTE再帰クエリの実行方法:
再帰的な終了は、ポイント・メンバーの位置決めに依存し、それが理解されると、再帰クエリの実行方法も理解されます.
上記の例の実行手順を見てみましょう.
- SELECT * FROM lmenu
この文は再帰クエリに入ります
- SELECT A.NAME,A.SENIOR,b.level+1 FROM MENU A,lmenu b
- where a.senior = b.name
最外層の文として、再帰的な第1層は、menuテーブルでクエリされたレコードの順序が次のようになると仮定して、MENUテーブルのレコードに基づいてループする必要があることは明らかです.
- name senior
- --- --------------------------------------------------
- NULL
-
-
-
1番目のレコード:
まず、再帰に入るかどうかを判断します.ファイルは位置決めポイントメンバー結果セットに含まれており、再帰条件に合致しないため、再帰に入らず、直接位置決めポイントメンバーセットからレコードを返します.
- select name,senior,0 level from menu where senior is null and name=' '
- name senior level
- --------------- ------------------------ -----------
- NULL 0
第二条記録:
すなわちNAME='新規'であり、位置決めポイントのメンバー結果セットに記録がなく、再帰に入ります.
現在のローの値を再帰メンバーに持ち込むには、次の手順に従います.
- SELECT A.NAME,A.SENIOR,b.level+1 level FROM MENU A,lmenu b
- where a.senior = b.name
- AND a.senior = ' '
- AND a.name=' '
再帰の関連条件はa.senior=b.nameであるため、b.name='ファイル'は、この条件で下位再帰に入ります.これは実際には最初のレコードの場合です.name='ファイル'は位置決め点の条件に合致するため、再帰は終了します.lmenu再帰メンバーをサブクエリで置き換えると、2番目のレコードのクエリ文は実際には次のようになります.
- SELECT a.name,a.senior,b.level+1 from menu a, (
- select name,senior,0 level from menu
- where senior is null and name=' '
- ) b
- where a.senior=b.name
- and a.senior = ' '
- and a.name=' '
name senior level----------------------------------------------------------------新規ファイル1
第三条記録:
NAME='現在の接続クエリーを使用する'は、同じように位置決めポイントの条件を満たしていないため、再帰的になります.
- SELECT A.NAME,A.SENIOR,b.level+1 FROM MENU A,lmenu b
- where a.senior = b.name
- AND a.senior = ' '
- AND a.name = ' '
同様に、現在のレコード条件を代入し、下位再帰b.name='新規'であり、'新規'は位置決め点条件に合致しないため、再帰を継続し、lmenu bはサブクエリを表す.
- select c.name,c.senior,d.level+1 level from menu c,lmenu d
- where c.senior = d.name
- and c.name = ' '
- and c.senior = ' '
上記の文に置き換えると、d.name='ファイル'は、再帰を継続する必要があるかどうかを再判断し、'ファイル'は再帰を終了する条件に合致するため、再帰を終了します.
サブクエリを使用して、3番目のレコードの再帰プロセスを次のように表します.
- SELECT a.name,a.senior,b.level+1 level FROM menu A,(
- select c.name,c.senior,d.level+1 level from menu c,(
- select name,senior,0 level from menu where senior is null and name=' '
- ) d
- where c.senior = d.name
- and c.name = ' '
- and c.senior = ' '
- ) b
- where a.senior = b.name
- and a.senior = ' '
- and a.name = ' '
name senior level
--------------------------------------------------------- -----------
現在の接続クエリーを使用して新規2を作成
第4条記録は第3条記録の再帰階層と全く同じである.