使用SQL完成
对于我的回答,我假设seq
是用于对菜单层次结构中的兄弟节点进行排序的,并且您提供的示例数据是错误的(没有两个兄弟节点可以具有相同的seq
值,即应该有UNIQUE (pid,seq)
)。因此,我将使用以下示例数据进行操作(使用INT
ID以简化问题):
INSERT INTO menu (id, pid, name, seq)
VALUES
(1, null, 'Menu 1', 1),
(2, null, 'Menu 2', 2),
(3, null, 'Menu 3', 3),
(4, 1, 'Sub Menu 1', 1),
(5, null, 'Menu 1', 9);
你需要使用WITH子句
来进行递归查询。在SQL中:
WITH RECURSIVE m AS (
SELECT
id,
ARRAY[seq] AS path,
name, 1 AS level,
'- ' || name AS display
FROM menu
WHERE pid IS NULL
UNION ALL
SELECT
menu.id,
path || seq,
menu.name,
m.level + 1 AS level,
repeat(' ', m.level) || '- ' || menu.name
FROM menu JOIN m ON m.id = menu.pid
)
SELECT *
FROM m
ORDER BY path;
这里可以查看查询结果,它是:
id |path |name |level |display |
---|------|-----------|------|---------------|
1 |{1} |Menu 1 |1 |- Menu 1 |
4 |{1,1} |Sub Menu 1 |2 | - Sub Menu 1 |
2 |{2} |Menu 2 |1 |- Menu 2 |
3 |{3} |Menu 3 |1 |- Menu 3 |
5 |{9} |Menu 1 |1 |- Menu 1 |
当然,还有其他的方法可以达到同样的效果。列说明:
- id:原始菜单项ID
- path:通向任何给定菜单项的路径(一个串联的seq值数组,假设它们在每个pid下是唯一的)
- name:菜单项的原始名称
- level:递归或嵌套级别(对于填充很有用)
- display:根据你的问题填充菜单项的显示
使用jOOQ完成此操作:
现在,你只需要将上面的内容翻译成jOOQ查询。
假设这些静态导入(像平常一样):
import static org.jooq.impl.DSL.*;
import static com.example.generated.Table.*;
as follows:
Field<Integer[]> path = array(MENU.SEQ).as("path");
Field<Integer> level = inline(1).as("level");
Field<String> display = inline("- ").concat(MENU.NAME).as("display");
Table<?> m = name("m").as(
select(MENU.ID, path, MENU.NAME, level, display)
.from(MENU)
.where(MENU.PID.isNull())
.unionAll(
select(
MENU.ID,
PostgresDSL.arrayAppend(path, MENU.SEQ),
MENU.NAME,
level.add(inline(1)),
repeat(inline(" "), level).concat(inline("- ")).concat(MENU.NAME))
.from(MENU)
.join(table(name("m"))).on(field(name("m", "id"), Integer.class).eq(MENU.PID)))
);
ctx.selectFrom(m).orderBy(path).fetch();
seq
内容真的正确吗?为什么Menu 1
和Menu 2
有相同的seq
值?我猜想seq
用于对任何给定菜单项的子项进行排序... - undefinedseq
有误。 - undefinedUNIQUE (pid, seq)
键! - undefined