2016-01-07 2 views
1

У меня есть иерархические данные, хранящиеся в моей таблице [AdjT] в SQL Server 2014. Общая глубина данных составляет 4 уровня и фиксирована.
т.е. [Родитель - Child1 - Child2 - Child3]Как использовать данные одного столбца для получения данных для другого столбца в инструкции SQL SELECT

Столбцы: Adjt {Id, ParentId, название, TypeM}
Вы можете увидеть данные в изображении. Data in table

несколько иерархий (как в TypeM) присутствуют в одной таблице (вы можете увидеть 2 родителей)

Что мне требуется?

Мне нужно получить все родительские «Название» для любого данного Ребенка.
например, ниже изображение показывает «иерархия» для Id: 4 для TypeM: AAA Expected Output

То, что я сделал до сих пор

Этот запрос дает мне ребенка строку и его непосредственного родителя.

select a.Title as P1, (select a1.Title from AdjT as a1 where a1.Id=a.ParentId) as P1 from Adjt as a where a.TypeM='AAA' and a.Id=4; 

так:
enter image description here

Вопрос:
Но когда я пытаюсь получить доступ к P3 на основе ParentID P2, я получаю сообщение об ошибке.

[Идентификатор нескольких частей "a1.ParentId" не может быть связан.]

в соответствии с приведенной ниже запроса:
select a.Title as P1 , (select a1.Title from AdjT as a1 where a1.Id=a.ParentId) as P2 , (select a2.Title from AdjT as a2 where a2.Id=a1.ParentId) as P3 --"a1.ParentId" ERROR from Adjt as a where a.TypeM='AAA' and a.Id=4;
Даже если я пишу, как P2.ParentId , это дает мне:

Идентификатор из нескольких частей "P2.ParentId" не может быть связан.

Что я могу сделать для того, чтобы это работало?

Обходной, который я использую в настоящее время
Я использую вложенный запрос, чтобы получить доступ к данным и иерархии, которые мне нужны.
Его выполнение по нижеследующему запросу:
select a.Title as P1 , (select a1.Title from AdjT as a1 where a1.Id=a.ParentId) as P2 , (select a2.Title from AdjT as a2 where a2.Id=(select a1.ParentId from AdjT as a1 where a1.Id=a.ParentId)) as P3 , (select a3.Title from AdjT as a3 where a3.Id=(select a2.ParentId from AdjT as a2 where a2.Id=(select a1.ParentId from AdjT as a1 where a1.Id=a.ParentId))) as P4 from Adjt as a where a.TypeM='AAA' and a.Id=4;
Есть ли лучший способ сделать это? Почему я могу получить доступ только к родительскому родительскому элементу первого столбца?
Я не могу редактировать схему таблицы или как хранить данные. Иерархия должна извлекаться снизу вверх, используя идентификатор листового узла, как показано выше.
Я попытался использовать CTE для получения иерархических данных, но я хочу, чтобы они были «столбцами», а не «строками». Преобразование этих строк CTE в столбцы в «коде» также не является вариантом.
Если кто-нибудь может предложить лучший способ сделать это, это было бы очень полезно.

Спасибо, что прочитали мой вопрос, любая помощь будет оценена по достоинству.

+0

Мой совет: внимательно посмотрите на ответ Рахула и убедитесь, что вы полностью понимаете, как работает «JOIN». Они являются неоценимой частью SQL. Многие подзапросы, которые вы используете, приведут к очень неаккуратным и трудно читаемым (и поддерживающим) кодам, которые, вероятно, будут работать очень плохо. Если вы собираетесь делать больше SQL-программирования в будущем, вы должны прочитать некоторые вступительные книги по этой теме. –

+0

Считаете ли вы использование [Иерархических данных] (https://msdn.microsoft.com/en-us/library/bb677173.aspx)? – shadow

ответ

1

Есть несколько методов, которые Вы должны будете достигнуть этого.

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

Дальше нам понадобится OUTER JOIN. Поскольку вы хотите искать с любого уровня, не всегда будет 3 родителя (например, Id 2 имеет только одного родителя). Обычное соединение отфильтровывает запись, если нет родителя. Внешние соединения избегают этого, возвращая NULL, когда нет соответствующей записи.

Я воссоздал ваши данные образца внутри таблицы VARIABLE. Это облегчает передачу кода примера.

Примеры данных

/* Table VAR creates sample records we can 
* all share. 
*/ 
DECLARE @Sample TABLE 
    (
     Id   INT PRIMARY KEY, 
     ParentId INT, 
     Title  VARCHAR(50), 
     TypeM  VARCHAR(3) 
    ) 
; 

/* Populate sample data. 
*/ 
INSERT INTO @Sample 
    (
     Id, 
     ParentId, 
     Title, 
     TypeM 
    ) 
VALUES 
    (1, 0, 'Parent 1 - [P1]', 'AAA'), 
    (2, 1, 'Child 1 - [C1] P1', 'AAA'), 
    (3, 2, 'Child 2 - [C2] C1 P1', 'AAA'), 
    (4, 3, 'Child 3 - [C3] C2 C1 P1', 'AAA'), 
    (5, 0, 'Parent 1 - [P2]', 'DDD'), 
    (6, 5, 'Child 1 - [C1] P2', 'DDD'), 
    (7, 6, 'Child 2 - [C2] C1 P2', 'DDD'), 
    (8, 7, 'Child 3 - [C3] C2 C1 P2', 'DDD') 
; 

Пример

/* Self joins can extract the hierarchy. 
* Outer joins ensure results are always returned. 
*/ 
SELECT 
    s1.Title AS [P1], 
    s2.Title AS [P2], 
    s3.Title AS [P3], 
    s4.Title AS [P4] 
FROM 
    @Sample AS s1 
     LEFT OUTER JOIN @Sample AS s2  ON s2.Id = s1.ParentId 
     LEFT OUTER JOIN @Sample AS s3  ON s3.Id = s2.ParentId 
     LEFT OUTER JOIN @Sample AS s4  ON s4.Id = s3.ParentId 
WHERE 
    s1.Id = 4 
; 

Попробуйте заменить WHERE ID = 4 с 3, чтобы увидеть внешнее соединение в действии.

+0

Спасибо. Это решило мою проблему. Значение NULL, возвращаемое в результате использования OUTER JOIN, было полезно. –

2

Вы имели в виду, чтобы сделать автообъединение как

select 
a.Title as P1 
a1.Title as Tital1, 
a2.Title as title2 

from AdjT a 
join AdjT a1 on a1.Id=a.ParentId 
join AdjT a2 on a2.Id=a1.ParentId 
where a.TypeM = 'AAA' 
and a.Id = 4; 
+0

Спасибо, что упростили это для меня. –

Смежные вопросы