JOOQ查询层次

时间:2018-11-30 02:34:42

标签: java sql postgresql jooq

我对表调用“ menu”有疑问。该表将父菜单项保存为pid null,其子项保存为pid =“ parent id”。

表结构为:

CREATE TABLE security.menu (
  id UUID NOT NULL,
  pid UUID DEFAULT NULL,
  url VARCHAR(100) DEFAULT NULL,
  name VARCHAR(50)DEFAULT NULL,
  seq NUMERIC DEFAULT NULL,
  state NUMERIC DEFAULT 1,
  created_at TIMESTAMP DEFAULT NULL,
  updated_at TIMESTAMP DEFAULT NULL,
  PRIMARY KEY (id)
);

数据是:

enter image description here

我需要建立一个JOOQ查询,以使用字段seqidpid以树模式检索数据。

我需要帮助来获取查询结果:

-Menu 1
     -Sub Menu 1
-Menu 2
-Menu 3
-Menu 1

上面的预期结果考虑了seq字段和pid字段

1 个答案:

答案 0 :(得分:4)

使用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 clause对此进行递归查询。在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;

The query output can be seen here。是:

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.*;

如下:

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();