すべてのノードとその階層情報の取得
distance: ルートノードからの距離
cf.
WITH RECURSIVEdepartment_tree AS (
SELECT d.*, dal.parent_id, 0 distance
FROM department d
JOIN department_adjacency_list dal USING (department_id)
WHERE dal.parent_id IS NULL
UNION ALL
SELECT d.*, dal.parent_id, dt.distance + 1
FROM department d
JOIN department_adjacency_list dal USING (department_id)
JOIN department_tree dt ON dal.parent_id =
dt.department_id
)
SELECT *
FROM department_tree;
MySQL :: MySQL 8.4 Reference Manual :: 15.2.20
WITH (Common Table Expressions)
13
特定のノードからの子孫ノードの取得
distance: ノード 10からの距離
WITH RECURSIVE department_tree AS (
SELECT d.*, dal.parent_id, 0 distance
FROM department d
JOIN department_adjacency_list dal USING (department_id)
WHERE d.department_id = 10
UNION ALL
SELECT d.*, dal.parent_id, dt.distance + 1
FROM department d
JOIN department_adjacency_list dal USING (department_id)
JOIN department_tree dt ON dal.parent_id =
dt.department_id
)
SELECT *
FROM department_tree;
15
特定のノードからの子孫ノードの取得
depth: ルートノードからの距離
SELECT d.*,dpe.path,
CHAR_LENGTH(dpe.path) - CHAR_LENGTH(REPLACE(dpe.path, '/',
'')) - 1 depth
FROM department d
JOIN department_path_enumeration dpe USING (department_id)
WHERE dpe.path LIKE CONCAT((
SELECT path
FROM department_path_enumeration
WHERE department_id = 10
), '%');
29
特定のノードの子ノードの取得
SELECT d.*
FROM departmentd
JOIN department_path_enumeration dpe USING (department_id)
WHERE dpe.path REGEXP CONCAT((
SELECT path
FROM department_path_enumeration
WHERE department_id = 10
), 'd+/$');
31
特定のノードの親ノードの取得
SELECT d.*
FROM departmentd
JOIN department_path_enumeration dpe USING (department_id)
WHERE dpe.path = (
SELECT CASE WHEN path = CONCAT(department_id, '/') THEN
NULL
ELSE
REGEXP_REPLACE(path, '^(.+/)d+/$', '$1')
END
FROM department_path_enumeration
WHERE department_id = 10
);
33
特定のノードからの子孫ノードの取得
SELECT d.*, dns.left,dns.right, dns.depth
FROM department d
JOIN department_nested_sets dns USING (department_id)
JOIN department_nested_sets dns2 ON dns.left BETWEEN
dns2.left AND dns2.right
WHERE dns2.department_id = 10;
43
特定のノードの子ノードの取得
SELECT d.*
FROM departmentd
JOIN department_nested_sets dns USING (department_id)
JOIN department_nested_sets dns2 ON dns.left BETWEEN
dns2.left AND dns2.right
WHERE dns2.department_id = 10
AND dns.depth = (
SELECT depth
FROM department_nested_sets
WHERE department_id = 10
) + 1;
45
特定のノードの親ノードの取得
SELECT d.*
FROM departmentd
JOIN department_nested_sets dns USING (department_id)
JOIN department_nested_sets dns2 ON dns2.left BETWEEN
dns.left AND dns.right
WHERE dns2.department_id = 10
AND dns.depth + 1 = (
SELECT depth
FROM department_nested_sets
WHERE department_id = 10
);
47
特定のノードからの子孫ノードの取得
distance: ノード 10からの距離
depth: ルートノードからの距離
SELECT d.*, dct.path_length distance, dct2.depth
FROM department d
JOIN department_closure_table dct
ON d.department_id = dct.descendant
JOIN (
SELECT descendant, COUNT(*) - 1 depth
FROM department_closure_table
GROUP BY descendant
) dct2
ON d.department_id = dct2.descendant
WHERE dct.ancestor = 10;
57
第9章 一歩進んだ論理設計 ~SQLで木構造を扱
う
『達人に学ぶDB設計徹底指南書』
『プログラマのためのSQLグラフ原論』
What are the options for storing hierarchical data
in a relational database? - Stack Overflow
67