SQLServerで、自分のテーブルに紐づくデータを再帰的に呼び出したい場合があります。
その場合は、共通テーブル式(CTE) を利用することで、再帰的にデータを取得できます。
1.再帰的な呼び出し
Webページのパンくずリスト(いまどこにいるかの道標)を考えると想像しやすいかもしれません。
例えば、下記のようなデータの構成の場合です。
これを実現するテーブル「パンくずリストテーブル」は、ページの情報と、親となるページのIDを持った構成となります。
- 【パンくずリストテーブル】
-
- ID
- ページのID (例:page-01)
- 名前
- ページ名称 (例:会社概要)
- URL
- ページのURL (例:http://goodtech.co.jp/company/)
- 親ID
- 親となるID (例:page-0)
こういった場合で、「親ID」をたどって全てのページの一覧を取得する方法が、「再帰的な呼び出し」と言います。
2.共通テーブル式(CTE)
SQL Server で、再帰的な呼び出しでデータを取得したい時に利用するのが、共通テーブル式(CTE)です。
共通テーブル式(CTE)は、下記のようなものになります。
- SQL文を実行した時のみに作成できる一時的なテーブル
- 自己参照(再帰的な呼び出し)が可能
- 結果を複数回参照できる
詳細は、Microsoft SQL Server 「共通テーブル式の使用」を参照ください。
3.テストデータの用意
まずは、パンくずリストテーブルを作成します。
-- パンくずリストテーブル作成 CREATE TABLE Breadcrumbs( Id varchar(10) NOT NULL, Name nvarchar(200) NOT NULL, Url nvarchar(1000) NOT NULL, ParentId varchar(10), CONSTRAINT [PK_Breadcrumbs] PRIMARY KEY CLUSTERED ( Id ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
次に、テストデータを登録します。
一番上のデータとなる「GoodTechトップページ」は、親ID(ParentId)を「NULL」にすることがポイントです。
-- パンくずリストデータ作成 INSERT INTO Breadcrumbs (Id, Name, Url, ParentId)VALUES('page-0', 'GoodTechトップページ', 'http://goodtech.co.jp/', NULL) INSERT INTO Breadcrumbs (Id, Name, Url, ParentId)VALUES('page-01', '会社概要', 'http://goodtech.co.jp/company-profile/', 'page-0') INSERT INTO Breadcrumbs (Id, Name, Url, ParentId)VALUES('page-02', '提供サービス', 'http://goodtech.co.jp/services/', 'page-0') INSERT INTO Breadcrumbs (Id, Name, Url, ParentId)VALUES('page-03', 'お知らせ', 'http://goodtech.co.jp/notices/', 'page-0') INSERT INTO Breadcrumbs (Id, Name, Url, ParentId)VALUES('page-0301', 'ホームページを公開しました', 'http://goodtech.co.jp/notices/greeting2/', 'page-03') INSERT INTO Breadcrumbs (Id, Name, Url, ParentId)VALUES('page-04', 'お問い合わせ', 'http://goodtech.co.jp/contact/', 'page-0') INSERT INTO Breadcrumbs (Id, Name, Url, ParentId)VALUES('page-06', 'サイトマップ', 'http://goodtech.co.jp/sitemap/', 'page-0')
データを全件取得すると、下記のようになります。
4.再帰的なデータの取得
下記SQLで、データを再帰的に取得できます。
-- 共通テーブル式(CTE)を利用して再帰的にデータを取得する。 declare @Id varchar(10) = 'page-0'; WITH Breadcrumbs_CTE AS ( SELECT b1.*, CAST(b1.Id AS nvarchar(4000)) AS IdPath, CAST(b1.Name AS nvarchar(4000)) AS NamePath FROM Breadcrumbs b1 WHERE b1.Id = @Id UNION ALL SELECT b2.*, Breadcrumbs_CTE.IdPath + ' - ' + b2.Id AS IdPath, Breadcrumbs_CTE.NamePath + ' > ' + b2.Name AS NamePath FROM Breadcrumbs b2 INNER JOIN Breadcrumbs_CTE ON b2.ParentId = Breadcrumbs_CTE.Id ) SELECT cte.IdPath, cte.NamePath, cte.Url, cte.Id, cte.ParentId FROM Breadcrumbs_CTE cte ORDER BY cte.IdPath
構文は、
WITH [一時テーブル名] AS ( [取得SQL] )
SELECT [列名] FROM [一時テーブル名]
となります。
WITH句のカッコ内で、データを取得します。
その際に、WITH句で指定した一時テーブル名を呼び出すことで、再帰的な呼び出しが可能になります。
WITH句の後のSELECT文は、一時テーブルの内容を表示するための式となります。
いかがでしたか?
試してみると、簡単で便利なものだということがわかります。
グッドテックでは、SQL Server を利用したシステム開発やチューニング、また、Azure SQL Database などについても、多数の実績があります。ご相談は無料で承っておりますので、お気軽にお問い合わせください。
コメント