【SQLレシピ】階層を持つテーブルでルートから指定した子までの列を連結する

ネコニウム研究所

PCを利用したモノづくりに関連する情報や超個人的なナレッジを掲載するブログ

【SQLレシピ】階層を持つテーブルでルートから指定した子までの列を連結する

2023-6-22 | , ,

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を保存する列を作って階層を表現する場合、親を辿る際にループしないように注意!