SQL recursive query on self referencing table (Oracle)
假设我有这个示例数据:
1 2 3 4 5 6 7 8 9 10 11 12 | | Name | ID | PARENT_ID | ----------------------------- | a1 | 1 | NULL | | b2 | 2 | NULL | | c3 | 3 | NULL | | a1.d4 | 4 | 1 | | a1.e5 | 5 | 1 | | a1.d4.f6 | 6 | 4 | | a1.d4.g7 | 7 | 4 | | a1.e5.h8 | 8 | 5 | | a2.i9 | 9 | 2 | | a2.i9.j10| 10 | 9 | |
我想选择从accountID=1开始的所有记录,因此预期结果是:
1 2 3 4 5 6 7 8 | | Name | ID | PARENT_NAME | PARENT_ID | ------------------------------------------- | a1 | 1 | NULL | NULL | | a1.d4 | 4 | a1 | 1 | | a1.e5 | 5 | a1 | 1 | | a1.d4.f6 | 6 | a1.d4 | 4 | | a1.d4.g7 | 7 | a1.d4 | 4 | | a1.e5.h8 | 8 | a1.e5 | 5 | |
号
我目前可以进行递归选择,但随后无法从父引用访问数据,因此无法返回父名称。我使用的代码是(改编为简单的示例):
1 2 3 4 | SELECT id, parent_id, name FROM tbl START WITH id = 1 CONNECT BY PRIOR id = parent_id |
我应该使用什么SQL进行上述检索?
未来探索者的附加关键字:选择由同一表中的父键表示的分层数据的SQL
用途:
1 2 3 4 5 6 7 8 9 | SELECT t1.id, t1.parent_id, t1.name, t2.name AS parent_name, t2.id AS parent_id FROM tbl t1 LEFT JOIN tbl t2 ON t2.id = t1.parent_id START WITH t1.id = 1 CONNECT BY PRIOR t1.id = t1.parent_id |
使用prior怎么样?
所以
1 2 3 4 | SELECT id, parent_id, PRIOR name FROM tbl START WITH id = 1 CONNECT BY PRIOR id = parent_id` |
代码>
或者如果你想得到根名称
1 2 3 4 | SELECT id, parent_id, CONNECT_BY_ROOT name FROM tbl START WITH id = 1 CONNECT BY PRIOR id = parent_id |
。
使用新的嵌套查询语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | WITH q(name, id, parent_id, parent_name) AS ( SELECT t1.name, t1.id, NULL AS parent_id, NULL AS parent_name FROM t1 WHERE t1.id = 1 UNION ALL SELECT t1.name, t1.id, q.id AS parent_id, q.name AS parent_name FROM t1, q WHERE t1.parent_id = q.id ) SELECT * FROM q |
你想这样做吗?
1 2 3 | SELECT id, parent_id, name, (SELECT Name FROM tbl WHERE id = t.parent_id) parent_name FROM tbl t START WITH id = 1 CONNECT BY PRIOR id = parent_id |
编辑另一个基于OMG的选项(但我认为它的性能是一样的):
1 2 3 4 5 6 7 8 9 10 11 12 13 | SELECT t1.id, t1.parent_id, t1.name, t2.name AS parent_name, t2.id AS parent_id FROM (SELECT id, parent_id, name FROM tbl START WITH id = 1 CONNECT BY prior id = parent_id) t1 LEFT JOIN tbl t2 ON t2.id = t1.parent_id |
号
这有点麻烦,但我相信这应该有效(没有额外的连接)。这假设您可以选择一个永远不会出现在相关字段中的字符作为分隔符。
你可以不用嵌套select来完成它,但是我发现这样做有点简单,它有四个对sys-connect-by-u-path的引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | SELECT id, parent_id, CASE WHEN lvl <> 1 THEN substr(name_path, instr(name_path,'|',1,lvl-1)+1, instr(name_path,'|',1,lvl) -instr(name_path,'|',1,lvl-1)-1) END AS name FROM ( SELECT id, parent_id, sys_connect_by_path(name,'|') AS name_path, level AS lvl FROM tbl START WITH id = 1 CONNECT BY PRIOR id = parent_id) |
。