2

У меня есть данные в автообъединении иерархической таблицы, где Континенты имеют много Страны имеют много Регионов имеет много Штатов много Города.Flatten иерархии на автообъединение таблицы

самоприсоединение структура таблицы:

|-------------------------------------------------------------| 
| ID | Name   | Type  | ParentID | IsTopLevel | 
|-------------------------------------------------------------| 
| 1 | North America | Continent | NULL  | 1   | 
| 12 | United States | Country | 1   | 0   | 
| 113 | Midwest  | Region  | 12  | 0   | 
| 155 | Kansas  | State  | 113  | 0   | 
| 225 | Topeka  | City  | 155  | 0   | 
| 2 | South America | Continent | NULL  | 1   | 
| 22 | Argentina  | Country | 2   | 0   | 
| 223 | Southern  | Region  | 22  | 0   | 
| 255 | La Pampa  | State  | 223  | 0   | 
| 777 | Santa Rosa | City  | 255  | 0   | 
|-------------------------------------------------------------| 

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

Ожидаемые результаты:

|------------------------------------------------------------------------------------| 
| Continent  | Country  | Region | State | City  | Bottom_Level_ID | 
|------------------------------------------------------------------------------------| 
| North America | United States | Midwest | Kansas | Topeka  | 234    | 
| South America | Argentina  | Southern | La Pampa | Santa Rosa | 777    | 
|------------------------------------------------------------------------------------| 

Есть несколько ключевых моментов, которые я должен уточнить.

  1. Каждая отдельная запись имеет нижний уровень и верхний уровень. Нет случаев, когда все пять типов не представлены для данного местоположения.

  2. Если я заполнил эти данные, я бы 50 записей для Северной Америки на государственном уровне, так что вы можете себе представить, насколько огромна эта таблица находится на уровне города на всех континентах планеты. Billions строк.

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

  4. Это старая база данных, 2005, и у меня нет системного администратора или управления схемой.

Мой КТР Код

--CTE 
;WITH Tree 
AS (
    SELECT ID, Name, ParentID, Type, 1 as Depth 
    FROM LocationTable 
    WHERE IsTopLevel = 1 
    UNION ALL 
    SELECT L.ID, L.Name, L.ParentID, L.Type, T.Depth+1 
    FROM Tree T 
    JOIN LocationTable L 
     ON L.ParentGUID = T.GUID 
) 

Хорошие твердые данные, в основном, удобном формате. НО тогда я должен думать об этом и не является структурой таблицы уже в этом формате, так почему я буду беспокоиться о том, чтобы сделать поиск дерева глубины, если бы я не собирался объединять записи вместе в одно и то же время?

В любом случае, здесь было все остальное.

Стержнем Покушение

;WITH Tree 
AS (
    SELECT ID, Name, ParentID, Type 
    FROM LocationTable 
    WHERE IsTopLevel = 1 
    UNION ALL 
    SELECT L.ID, L.Name, L.ParentID, L.Type 
    FROM Tree T 
    JOIN LocationTable L 
     ON L.ParentGUID = T.GUID 
) 
select * 
from Tree 
pivot (
    max(Name) 
    for Type in ([Continent],[Country],[Region],[State],[City]) 
) pvt 

И теперь у меня есть все, что по типу в колонке, с нулями для всего остального. Поскольку я боролся с ранее, мне нужно отфильтровать/присоединиться к данным CTE, прежде чем я попытаюсь установить точку опоры, но я понятия не имею, с чего начать эту пьесу. Все, что я пробовал, это soooooooooo sloooooooow.

Каждый раз, когда я думаю, что я понимаю CTE и Pivot, что-то новое делает меня чрезвычайно униженным. Пожалуйста, помогите мне.; ;

+0

было бы возможно написать целую партию в новом DataTable с 5 столбцов * бок -боковая сторона*? Если я правильно вас понимаю, есть ** всегда ** пять уровней сверху вниз ... Гибкость дерева и рекурсивный подход вообще не нужны ... – Shnugo

+0

Я не могу изменить схему. – BlueCucumber

ответ

3

Если ваша структура настолько чист, как вы описать его (без пробелов, 5 уровней всегда) вы могли бы пойти по легкому пути:

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

Убедитесь, что есть указатель на ParentID и ID!

DECLARE @tbl TABLE(ID INT,Name VARCHAR(100),Type VARCHAR(100),ParentID INT,IsTopLevel BIT); 
INSERT INTO @tbl VALUES 
(1,'North America','Continent',NULL,1) 
,(12,'United States','Country',1,0) 
,(113,'Midwest','Region',12,0) 
,(155,'Kansas','State',113,0) 
,(225,'Topeka','City',155,0) 
,(2,'South America','Continent',NULL,1) 
,(22,'Argentina','Country',2,0) 
,(223,'Southern','Region',22,0) 
,(255,'La Pampa','State',223,0) 
,(777,'Santa Rosa','City',255,0); 

SELECT Level1.Name AS Continent 
     ,Level2.Name AS Country 
     ,Level3.Name AS Region 
     ,Level4.Name AS State 
     ,Level5.Name AS City 
     ,Level5.ID AS Bottom_Level_ID 
FROM @tbl AS Level1 
    INNER JOIN @tbl AS Level2 ON Level1.ID=Level2.ParentID 
     INNER JOIN @tbl AS Level3 ON Level2.ID=Level3.ParentID 
      INNER JOIN @tbl AS Level4 ON Level3.ID=Level4.ParentID 
       INNER JOIN @tbl AS Level5 ON Level4.ID=Level5.ParentID 
WHERE Level1.ParentID IS NULL 

Результат

Continent  Country   Region  State  City  Bottom_Level_ID 
North America United States Midwest  Kansas  Topeka  225 
South America Argentina  Southern La Pampa Santa Rosa 777 
+0

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

+0

Миллиардов строк довольно много ... Есть ли указатели на ID и ParentID? Насколько я понял, вам нужно привязать местоположение к адресам. Таким образом, вам не нужен полный результат, просто * back-chain * от 'Bottom_Level_ID'. Верный? Это должно работать мгновенно ... В любом случае это ** должно быть быстрее любого рекурсивного подхода, который является скрытым RBAR ... Одним из хороших вариантов может быть - если это будет работать для вас - использовать мой запрос (добавьте alle LevelIDs) и используйте 'SELECT ... INTO NewTable FROM ...'. Это может работать в течение нескольких часов, но только один раз. Поместите индексы, и у вас будет источник света с быстрым источником ... – Shnugo

0

Другое решение с КТР может быть:

;WITH Tree 
AS (
    SELECT cast(NULL as varchar(100)) as C1, cast(NULL as varchar(100)) as C2, cast(NULL as varchar(100)) as C3, cast(NULL as varchar(100)) as C4, Name as C5, ID as B_Level 
    FROM LocationTable 
    WHERE IsTopLevel = 1 
    UNION ALL 
    SELECT T.C2, T.C3, T.C4, T.C5, L.Name, L.ID 
    FROM Tree T 
    JOIN LocationTable L 
     ON L.ParentID = T.B_Level 
) 
select * 
from Tree 
where C1 is not null 
+0

Msg 240, уровень 16, состояние 1, строка 1 Типы не совпадают между якорем и рекурсивным часть в столбце «C4» рекурсивного запроса «Дерево». – BlueCucumber

+0

Вы правы. Я исправил свою ошибку, заменив NULL на листинг (NULL как varchar (100)). Теперь это работает. – Polux2