JOOQ Иерархия запросов - PullRequest
       9

JOOQ Иерархия запросов

0 голосов
/ 30 ноября 2018

У меня проблема с вызовом таблицы "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)
);

и данныеis:

enter image description here

Мне нужно создать запрос JOOQ для извлечения данных в режиме дерева, используя поля seq, id и pid.

Мне нужна помощь, чтобы получить результат запроса:

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

Ожидаемый результат, приведенный выше, учитывает поле seq и поле pid

1 Ответ

0 голосов
/ 03 декабря 2018

Делаем это с помощью SQL

Для моего ответа я собираюсь предположить, что seq используется для упорядочения братьев и сестер в иерархии вашего меню, и что ваши примерные данные неверны (два брата не могутимеют одинаковое значение seq, т.е. должно быть UNIQUE (pid, seq). Итак, я поработаю с этими примерами данных (INT идентификаторы для простоты):

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;

Вывод запроса можно увидеть здесь . Это:

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: идентификатор исходного пункта меню
  • 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();
...