【SQLレシピ】階層を持つテーブルでルートから指定した子までの列を連結する
SQLで階層を持つテーブルでルートから指定した子までの列を連結したい!
「日本 - 関東 - 東京」みたいに「東京」を指定したらフルパスを取得する的な!
概要
この記事では、SQLで階層を持つテーブルでルートから指定した子までの列を連結する手順を掲載する。
仕様書
環境
- SQLite 3.35.5
- SQL Server 15.0.2000
手順書
下表のようを「国~方面~都道府県名」を管理してるテーブルbase
を例にする。
列名 | データ型 | 備考 |
---|---|---|
id | INTEGER | ユニークな連番 |
parent_id | INTEGER | 親のid。0はルート。 |
name | TEXT | 名前 |
登録してるデータは下記のとおり。
id | parent_id | name |
---|---|---|
1 | 0 | 日本 |
2 | 1 | 北海道・東北 |
3 | 2 | 北海道 |
4 | 2 | 青森県 |
5 | 2 | 岩手県 |
6 | 2 | 宮城県 |
7 | 2 | 秋田県 |
8 | 2 | 山形県 |
9 | 2 | 福島県 |
10 | 1 | 関東 |
11 | 10 | 茨城県 |
12 | 10 | 栃木県 |
13 | 10 | 群馬県 |
14 | 10 | 埼玉県 |
15 | 10 | 千葉県 |
16 | 10 | 東京都 |
17 | 10 | 神奈川県 |
18 | 1 | 中部 |
19 | 18 | 新潟県 |
20 | 18 | 富山県 |
21 | 18 | 石川県 |
22 | 18 | 福井県 |
23 | 18 | 山梨県 |
24 | 18 | 長野県 |
25 | 18 | 岐阜県 |
26 | 18 | 静岡県 |
27 | 18 | 愛知県 |
28 | 1 | 近畿 |
29 | 28 | 三重県 |
30 | 28 | 滋賀県 |
31 | 28 | 京都府 |
32 | 28 | 大阪府 |
33 | 28 | 兵庫県 |
34 | 28 | 奈良県 |
35 | 28 | 和歌山県 |
36 | 1 | 中国 |
37 | 36 | 鳥取県 |
38 | 36 | 島根県 |
39 | 36 | 岡山県 |
40 | 36 | 広島県 |
41 | 36 | 山口県 |
42 | 1 | 四国 |
43 | 42 | 徳島県 |
44 | 42 | 香川県 |
45 | 42 | 愛媛県 |
46 | 42 | 高知県 |
47 | 1 | 九州・沖縄 |
48 | 47 | 福岡県 |
49 | 47 | 佐賀県 |
50 | 47 | 長崎県 |
51 | 47 | 熊本県 |
52 | 47 | 大分県 |
53 | 47 | 宮崎県 |
54 | 47 | 鹿児島県 |
55 | 47 | 沖縄県 |
今回は、「東京」のidを指定して、そのidが属する親の名前と自分の名前をルートから並べえて連結するクエリを紹介する。
レコードの間には -
を挿入する。
下記はSQLite。
WITH hierarchy AS (
SELECT
id,
parent_id,
CAST(name AS TEXT) AS path
FROM
base
WHERE
parent_id = 0
UNION ALL
SELECT
t.id,
t.parent_id,
h.path || '-' || t.name
FROM
base t
INNER JOIN hierarchy h ON t.parent_id = h.id
)
SELECT path FROM hierarchy WHERE id = 16;
下記はSQL Server。
WITH hierarchy AS (
SELECT
id,
parent_id,
CASTname AS VARCHAR(255)) AS path
FROM
base
WHERE
parent_id = 0
UNION ALL
SELECT
t.id,
t.parent_id,
CAST(h.path + '-' + CAST(t.name AS VARCHAR(255)) AS VARCHAR(255))
FROM
base t
INNER JOIN hierarchy h ON t.parent_id = h.id
)
SELECT path FROM hierarchy WHERE id = 16;
クエリを実行すると下記のように名前が連結されて出力される。
path |
---|
日本 - 関東 - 東京 |
SQLiteとSQL Serverの違いは型のCAST
の部分と文字列の連結の部分。今回の様に文字列型の列を連結する分にはCAST
は不要なんだけども、整数型などの文字列型以外を連結する場合は文字列型にCAST
する必要がある。メモとして残してる。
まとめ(感想文)
このテーブルの様に親のid
を保存する列を作って階層を表現する場合、親を辿る際にループしないように注意!