2016-08-02 5 views
-2

ввода Таблица: РегионыКак получить нужные записи?

+---------------+---------------+---------- +-----------+ 
    | Child   | Parent  | Level  | levelname| 
    +---------------+---------------+---------- +-----------+ 
    | All Region | All Region | 1   | national | 
    | Africa Region | All Region | 2   | region | 
    | America  | All Region | 2   | region | 
    | Asia   | All Region | 2   | region | 
    | Europe Region | All Region | 2   | region | 
    | Africa  | Africa Region | 3   | Subregion | 
    | Asia Pacific | Asia   | 3   | Subregion | 
    | Europe  | Europe Region | 3   | Subregion | 
    | North America | America  | 3   | Subregion | 
    | South America | America  | 3   | Subregion | 
    | Argentina  | South America | 4   | Country | 
    | Australia  | Asia Pacific | 4   | Country | 
    | Pakistan  | Asia Pacific | 4   | Country | 
    | South Africa | Africa  | 4   | Country | 
    | Tunisia  | Africa  | 4   | Country | 
    | Uruguay  | South America | 4   | Country | 
    +-------------------------------------------------------+ 

Здесь регионы имеют 4 уровня

  • Все области
  • Регион
  • Субрегион
  • Страна

    у них есть 0,1,2 и 3 предка, например, страна имеет субрегион, регион и allregion как предки, предположим, что мы даем «Уругвай», тогда выход будет в Южной Америке, Америке, во всем регионе.

Теперь мне нужен запрос для этой таблицы, которая будет извлекать все предки для данного «ребенок»

+4

И где вы застряли? Что вы пробовали? Пожалуйста, помните, что StackOverflow не является бесплатным сервисом кодирования. –

+1

Сделайте четыре таблицы-самосоединение, чтобы получить все четыре уровня в одной строке или рекурсивный запрос, чтобы получить их в строках. – dnoeth

+0

Этот вывод таблицы выглядит подозрительно, как MySQL (который не является SQL-сервером) – Duston

ответ

4

Лучше рекурсивный КТР:

With recRegions AS 
(
    /*Recursive Seed*/ 
    SELECT 
     Child, 
     Parent, 
     Level, 
     0 as Depth, 
     CAST(Child as VARCHAR(5000)) as Path 
    FROM 
     Regions 
    WHERE 
     Child=<WhateverChildYouAreWanting> 

    UNION ALL 

    /*Recursive Term*/ 
    SELECT 
     Regions.Child, 
     Regions.Parent, 
     Region.Level, 
     recRegions.Depth + 1, 
     recRegions.Path || '>' || Region.Child 
    FROM 
     recRegions 
     INNER JOIN Regions on 
      recRegions.parent = Regions.Child 
    Where recRegions.Depth < 10 
) 

Select Parent as Ancestors FROM recRegions; 

Рекурсивные запросы могут быть немного сложным, чтобы сначала обернуть голову, но если вы разложите его кусочки, это имеет смысл:

  1. Рекурсивное семя - это той части, где мы получаем первый член, которым мы являемся. В вашем случае нам просто нужна запись, в которой ребенок является страной, которую вы хотите запросить.
  2. Рекурсивный термин - это та часть, где запрос обращается к себе. Он присоединяет рекурсивный CTE recRegions к вашей таблице Region, соединяющий дочерний элемент с родительским. БД ударит по этому рекурсивному термину, пока больше записей не вернется, а это значит, что мы поднялись по всей иерархии.
  3. Окончательный оператор select просто отбрасывает записи из вашего рекурсивного запроса. Вы хотели всех предков, так что это были бы все записи полей Parent.

Как правило, когда вы видите таблицу с макетом child | parent | attributes | of | that | relationship, вы можете обратиться к супермощному рекурсивному CTE, чтобы иметь в виду все это.

Как @dnoeth упомянул в комментариях Q, вы также можете присоединиться к таблице регионов 4 раза, так как ваша иерархия кажется всего лишь 4 глубиной. Рекурсивный запрос не заботится о глубине, поэтому, если вы добавите больше глубины в свою иерархию, вам не придется редактировать свой SQL, чтобы вытащить предков.


Обновлено добавить поле «Глубина» для отслеживания рекурсии и остановки после 10. Также добавлено поле «Path», чтобы отслеживать иерархию, как это застроенной от ребенка. Если у вас есть проблемы с вашим велосипедным иерархии (ребенком отчетностью родителя, который сообщает ребенок вызывает бесконечный цикл), то вы можете использовать следующий SQL заявление вместо SELECT parent FROM версии выше:

SELECT * FROM recRegions; 

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

+1

Замечательный пример и объяснение! – Nicarus

+0

@JNveill В процессе выполнения он показывает: «Операция завершена. Максимальная рекурсия 100 исчерпана до завершения заявки», я думаю, что она входит в бесконечный цикл, не могли бы вы проверить это? – BlackCat

+1

@ Zahid Я обновил, чтобы остановить рекурсии после того, как мы достигли 10 глубины. Я добавил поле с именем 'Depth', которое будет отслеживать, насколько глубоко мы находимся в рекурсии и убиваем рекурсивный термин с помощью предложения WHERE. Я предполагаю, что у вас есть ребенок, который отчитывается перед родителем, который отчитывается перед оригинальным ребенком (это называется «Велоспорт», и это не забавно иметь дело). Я также добавляю поле «Путь», которое будет отслеживать отношения между родителями и дочерними элементами по мере продвижения рекурсии, чтобы вы могли узнать, где находится цикл. – JNevill