SQL/Laravel: получить родителей в древовидной структуре данных

Всем привет) Я использую Laravel, MariaDB.

Например, у нас есть такая таблица, скажем категории.

идентификатор имя _ft _rgt родительский_ид путь is_folder 1373 Окна 1 10 НУЛЕВОЙ 1373 1 1374 Стеклопакет 2 7 1373 1373.1374 1 1375 Аксессуары 8 9 1373 1373.1375 1 1376 Монтаж 3 4 1374 1373.1374.1376 0 1377 Корректирование 5 6 1374 1373.1374.1377 0

Модель «Категории» использует признак Kalnoy\Nestedset\NodeTrait. В приведенном ниже коде построитель запросов уже содержит базовые фильтры (например, по имени).

if (!empty($filters['recursiveSearch']) && CommonService::parseBoolean($filters['recursiveSearch']) === true) {
/** @var QueryBuilder $query */
}

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

Например: по имени фильтра=adjust мы получаем строку Корректировка. с recursiveSearch вам также необходимо получить Windows и Glass unit.


Запрос также может иметь родительский идентификатор фильтра. Если parentId=null&name=adjust&recursiveSearch=true, то он должен вернуть Windows

Пожалуйста помоги :)

Сначала я думал сделать просто with('ancestors'), но результат попадает в отношения и должен быть в основном запросе.

Потом я сделал дополнительный запрос, получил результат первой выборки, получил pluck('ancestors') и уже подставил их идентификаторы в результирующий запрос. Это сработало, но если в первоначальной выборке будет, например, 1000 записей и у каждой будет по 3 родителя, то в итоге будет где-то по 3000 ID.

Вы можете использовать рекурсивный запрос CTE.

Olivier 03.08.2024 10:07
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
1
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

По идее, не принимая во внимание Laravel, вы можете сделать это без рекурсии, поскольку у вас есть полный путь для каждой строки.

идентификатор имя _ft _rgt родительский_ид путь is_folder 1373 Окна 1 10 нулевой 1373 1 1374 Стеклопакет 2 7 1373 1373.1374 1 1375 Аксессуары 8 9 1373 1373.1375 1 1376 Монтаж 3 4 1374 1373.1374.1376 0 1377 Корректирование 5 6 1374 1373.1374.1377 0
select p.*
from categories c
inner join categories p on
    find_in_set(cast(p.id as char),replace(c.path,'.',','))>0
where c.id=1377
идентификатор имя _ft _rgt родительский_ид путь is_folder 1373 Окна 1 10 нулевой 1373 1 1374 Стеклопакет 2 7 1373 1373.1374 1 1377 Корректирование 5 6 1374 1373.1374.1377 0

рабочий пример

Проще сделать это с помощью 2 запросов

  1. Возьмите путь к желаемому идентификатору
select path from categories where id=1377

Вывод: «1373.1374.1377».

2. Опросить всех родителей с параметром «1373,1374,1377».

select *
from categories
where  find_in_set(cast(id as char),'1373,1374,1377')>0

Запрос идентификатора и всех детей

select *
from categories c
where  find_in_set(cast(1374 as char),replace(c.path,'.',','))>0
идентификатор имя _ft _rgt родительский_ид путь is_folder 1374 Стеклопакет 2 7 1373 1373.1374 1 1376 Монтаж 3 4 1374 1373.1374.1376 0 1377 Корректирование 5 6 1374 1373.1374.1377 0

рабочий пример

$query->join('categories as p', function ($join) {
    $join->on(DB::raw("FIND_IN_SET(CAST(p.id AS CHAR) COLLATE utf8mb4_unicode_ci, REPLACE(categories.path COLLATE utf8mb4_unicode_ci, '.', ','))"), '>', DB::raw('0'));
})
    ->addSelect('p.*')
    ->distinct();

Это сработало в Ларавеле.

Другие вопросы по теме