С RECURSIVE SELECT через вторичную таблицу - PullRequest
1 голос
/ 27 февраля 2020

Я испытываю трудности с тем, чтобы собрать это воедино. Я не разбираюсь в базах данных или сложных запросах.

База данных

Я использую последнюю версию MariaDB.

У меня есть такая конфигурация таблицы базы данных, представляющая иерархическая структура данных:

|----------------------|
| fieldsets            |
|----+-----------------|
| id | parent_field_id |
|----+-----------------|
| 1  | NULL            |
| 2  | 1               |
|----------------------|

|-------------------------|
| fields                  |
|----+--------------------|
| id | parent_fieldset_id |
|----+--------------------|
| 1  | 1                  |
| 2  | 1                  |
|-------------------------|

Проблема

Я пытаюсь собрать рекурсивный запрос. Мне нужно выбрать каждый набор полей в данной иерархии. Например, в приведенном выше урезанном примере я хочу выбрать набор полей из id = 1 и каждый потомок набора полей.

Идентификаторы следующей ступени на любом заданном уровне в иерархии получаются только через столбцы вторичной таблицы.

Таблица fieldsets не содержит столбца, по которому я могу напрямую получить все дочерние элементы fieldsets. Мне нужно получить все fields, которые являются потомками данного fieldset, а затем получить fieldsets, которые являются потомками этого field.

Лучшая иллюстрация проблемы

Этот запрос не работает из-за сообщенной ошибки: «Ограничения, наложенные на рекурсивные определения, нарушаются для таблицы all_fieldsets»

Однако, это действительно иллюстрирует, что мне нужно сделать, чтобы получить всех потомков fieldsets в иерархии (помните, набор полей не содержит столбец для своего родителя fieldset, поскольку fieldset не может иметь fieldset в качестве прямого родителя. Вместо этого fieldset имеет parent_field_id, который указывает на строку в таблице fields, и эта строка в таблице fields соответственно имеет столбец с именем parent_fieldset_id, который указывает на строку назад в таблице fieldsets, которая считается родительской fieldset для fieldset, просто косвенный родитель.

WITH RECURSIVE all_fieldsets AS (
    SELECT fieldsets.* FROM fieldsets WHERE id = 125
    UNION ALL
    SELECT fieldsets.* FROM fieldsets
    WHERE fieldsets.parent_field_id IN (
        SELECT id FROM fields f
        INNER JOIN all_fieldsets afs
        WHERE f.parent_fieldset_id = afs.id
    )
)
SELECT * FROM all_fieldsets

Моя попытка

У меня есть запрос (который не работает):

WITH RECURSIVE all_fieldsets AS (
    SELECT fieldsets.* FROM fieldsets WHERE id = 125
    UNION
    SELECT fieldsets.* FROM fieldsets WHERE fieldsets.id IN (SELECT fs.id FROM fieldsets fs LEFT JOIN fields f ON f.id = fs.parent_field_id WHERE f.parent_fieldset_id = fieldsets.id)
)
SELECT * FROM all_fieldsets

Мой Исследования

У меня тоже тяжелые времена найти пример, который подходит для моего варианта использования. Существует так много результатов для иерархических структур, в которых одна таблица имеет отношение только к себе, а не через вторичную таблицу, как в моем случае. Трудно, когда вы не знаете правильных терминов для определенных понятий, и любое объяснение непрофессионала, по-видимому, приводит к слишком большому количеству результатов касательного поиска.

Моя просьба

Я был бы чрезвычайно благодарен всем, кто может укажите, где я ошибаюсь, и, возможно, предложите схему запроса, который будет работать.

Ответы [ 2 ]

0 голосов
/ 27 февраля 2020

Я вернулся домой с работы, и я просто не мог это записать!

Но из этого вышло решение.

Я настоятельно рекомендую прочитать этот ответ о рекурсивных запросах, чтобы получить лучшее представление о том, как они работают, и что означает синтаксис. Довольно блестяще объяснил: Как выбрать с помощью предложения WITH RECURSIVE

Решение

WITH RECURSIVE all_fieldsets AS (
    SELECT * FROM fieldsets fs
        WHERE id = 59
    UNION ALL
    SELECT fs.* FROM fieldsets fs
        INNER JOIN all_fieldsets afs
        INNER JOIN fields f
            ON f.parent_fieldset_id = afs.id
            AND fs.parent_field_id = f.id
)
SELECT * FROM all_fieldsets

Мне пришлось использовать объединения, чтобы получить информацию из таблицы fields, чтобы получить следующий уровень в иерархии, а затем делать это рекурсивно, пока в рекурсивном запросе не будет пустого результата.

0 голосов
/ 27 февраля 2020

Основная проблема, которую я вижу с вашим текущим кодом, состоит в том, что рекурсивная часть CTE (запрос, который появляется после объединения) не выбирает из рекурсивного CTE, когда это должно быть. Рассмотрите эту обновленную версию:

WITH RECURSIVE all_fieldsets AS (
    SELECT * FROM fieldsets WHERE id = 125
    UNION ALL
    SELECT f1.*
    FROM fieldsets f1
    INNER JOIN all_fieldsets f2
        ON f1.parent_field_id = f2.id
)

SELECT *
FROM all_fieldsets;

Обратите внимание, что объединение в рекурсивной части CTE связывает данную запись-потомка в fieldsets со своим родителем в CTE.

...