3

Теперь у нас есть вопрос, который мы обычно используем для поддержания родительского отношения к потомству, т. Е. Мы сохраняем все сущности в одной таблице с столбцом parent_id, и все топ-родители большинства имеют в столбце parent_id это хорошо и нормализованный метод я согласен, но есть и недостаток, он медленный и неэффективный. В основном это вызвано рекурсией, как для каждого родителя, мы должны выполнить запрос снова и снова, чтобы сделать это деревоПолучить верхнюю часть родительского элемента на n-й дочерний идентификатор?

SELECT id FROM `table` WHERE parent_id=something 

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

Итак, мой вопрос: можем ли мы сделать это с одним запросом базы данных для дерева (объединения или подзапросы)?

  • если мы знаем глубину или если мы не знаем глубины?
  • если возможно, то как мы можем получить самый верхний родительский (т.е. parent_id = 0) любого ребенка?
  • Если это невозможно, то почему эта техника настолько известна, хотя у нее есть недостатки или у нас есть другое решение для этого?

    Я добавил SQL скрипки, но он имеет только схему

FIDDLE

+3

В отличие от некоторых других СУБД, MySQL не поддерживает рекурсивные функции так, не очень хорошо подходит для эта модель «списка смежности» для хранения иерархических данных. Вы должны подумать о перестройке своей схемы, чтобы внедрить иерархическую структуру в форму, которую может использовать MySQL, например, «вложенные наборы» или «транзитивные закрытия». – eggyal

+0

@eggyal, но теперь многие многие из них выполняют эту технику, так как наиболее часто используемый Wordpress также обеспечивает уровень n-го уровня, уровень страницы и уровень категории, поэтому мой вопрос заключается в том, как лучше хранить и получать дерево без запуска нескольких запросов? –

+0

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

ответ

3

Я не знаю, если это возможно с MYSQL, я работал в основном с SQL Server в моей карьере. В SQL Server это можно сделать только с одним запросом, используя оператор WITH.

Это свидетельствует о том, как получить все дети объекта (ID = 3) на всех уровнях

With pa as (
    select pa1.* 
    From prarent as pa1 
    Where id = 3 
    union all 
    select pa2.* 
    from pa join prarent as pa2 on pa.id = pa2.parent_id 
) 
select * from pa where pa.id != 3 

DEMO

Другой пример, чтобы получить все родители объекта (ID = 7) до самый верхний

With pa as (
    select pa1.* 
    From prarent as pa1 
    Where id = 7 
    union all 
    select pa2.* 
    from pa join prarent as pa2 on pa.parent_id = pa2.id 
) 
select * from pa where pa.id != 7 

DEMO

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

With pa as (
    select pa1.* 
    From prarent as pa1 
    Where id = 7 
    union all 
    select pa2.* 
    from pa join prarent as pa2 on pa.parent_id = pa2.id 
) 
select top 1 * 
from pa 
where pa.id != 7 
order by id asc 

В этом примере, я предполагаю, что идентификатор пошагово и я использую простой способ (только для демонстрационных целей), чтобы получить верхний с помощью order by. Вы можете использовать другую технику в зависимости от дизайна вашей базы данных.

DEMO

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

+0

Большое спасибо, если вы когда-либо знаете, что такая функция возможна в mysql, тогда отредактируйте этот ответ, и вот ваша награда :) –

+0

@dianuj: большое спасибо –

0

Если у вас есть много уровней, или много данных, это будет непрактично.

В противном случае вы можете попытаться подражать тому, что делают рекурсивные функции. Даже если вы не получите такую ​​же производительность, это не имеет значения, если у вас мало данных или слишком много уровней.

Общая процедура будет выглядеть следующим образом:

  1. Для данного родителя, выберите запись с этим идентификатором
  2. Кроме того, выберите записи с тем, как parent_id и UNION это с предыдущим
  3. Подзапрос на шаге № 2 дает детям первого уровня, поэтому вы можете написать запрос, который выбирает их идентификаторы, и использовать это как подвыбор в третьем запросе, который говорит «где PARENT_ID IN (sub-select) "
  4. Это будет аналогично шагу № 3 и пойдет по этому пути

Это будет выглядеть примерно так: (see the Fiddle here)

select * 
from prarent P0 
where id = 3 

union 

select * 
from prarent P1 
where parent_id = 3 

union 

select * 
from prarent P2 
where parent_id in 
( select distinct id 
    from prarent P1 
    where p1.parent_id = 3 
) 

union 

select * 
from prarent P3 
where parent_id in 
( select distinct id 
    from prarent P2 
    where parent_id in 
    ( select distinct id 
     from prarent P1 
     where p1.parent_id = 3 
    ) 
) 
+0

, если вы видите, что у вас есть соединения глубины-1 в запросе с дополнительными выборами, и вы уже упоминали в своем ответе ** Если у вас много уровней или много данных, это будет непрактично. ** Я хочу, чтобы общий решение, если нет, то почему этот метод настолько популярен? –

+0

Если логарифмическая струя является деревом, то есть несколько альтернатив, которые по-прежнему гибкие. Практически говоря, когда я использовал структуру «спецификации», прецеденты были такими, что фокусировались на определенном количестве уровней и, если потребуется, сверлят вниз. Фактически, я бы, вероятно, сохранил эту структуру, даже если база данных не предлагала SQL с легкой рекурсией. Если у вас есть возможность смешать SQL с некоторым кодом 3-G (даже если это в хранимой процедуре), производительность в большинстве случаев является значительной проблемой. Сложность в коде, но не проблема производительности. –