2017-02-03 3 views
0

Я борюсь с подготовкой одного SQL-запроса, который должен возвращать ожидаемые данные за один снимок.Напишите SQL-запрос, чтобы получить только записи Super Child из таблицы

Мое требование состоит в том, чтобы получить данные из таблицы SQl с именем JobCollection таким образом, чтобы возвращаемые данные были выделены зеленой рамкой на изображении ниже.

Эти данные организованы в виде родительского ребенка. Как вы видите ниже,

  • JCId 1 является ParentID JCId 3,4,5. То же, что JCId 2 является ParentID JCId 6,7.
  • Также JCId 3,4,5 также являются ParentId 8,9,10,11,12 и так далее.

Условия:

  • Я хочу, чтобы получить только те записи из таблицы JobCollection которой JCId не родитель каких-либо дополнительных записей.

Как подчеркивается в зеленой рамке, JCId 8,9,10,11 и 12 не являются родителем какой-либо записи

Также зеленая граница подчеркивает супер ребенка из JCId 1 и не JCId 2

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

enter image description here

Update:

Еще один пример

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

enter image description here

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

ответ

1

Может быть, немного больше, чем нужно , но при желании вы можете уменьшить его.

Хитрость здесь заключается в использовании ключей диапазона R1/R2.

Declare @YourTable table (JCId int,JCParentId int,JCName varchar(50)) 
Insert into @YourTable values 
(1, NULL,'A') 
,(2, NULL,'B') 
,(3, 1 ,'A1') 
,(4, 1 ,'A2') 
,(5, 1 ,'A3') 
,(6, 2 ,'B1') 
,(7, 2 ,'B2') 
,(8, 3 ,'A11') 
,(9, 3 ,'A12') 
,(10, 4 ,'A21') 
,(11, 5 ,'A31') 
,(12, 5 ,'A32') 
,(13, 6 ,'B11') 
,(14, 6 ,'B12') 
,(15, 7 ,'B21') 
,(16, 7 ,'V22') 

Declare @Top int   = 1 --null  --<< Sets top of Hier Try 3 
Declare @Nest varchar(25) = '|-----' --<< Optional: Added for readability 

;with cteP as (
     Select Seq = cast(10000+Row_Number() over (Order by JCName) as varchar(500)) 
      ,JCId 
      ,JCParentId 
      ,Lvl=1 
      ,JCName 
     From @YourTable 
     Where IsNull(@Top,-1) = case when @Top is null then isnull(JCParentId ,-1) else JCId end 
     Union All 
     Select Seq = cast(concat(p.Seq,'.',10000+Row_Number() over (Order by r.JCName)) as varchar(500)) 
      ,r.JCId 
      ,r.JCParentId 
      ,p.Lvl+1 
      ,r.JCName 
     From @YourTable r 
     Join cteP p on r.JCParentId = p.JCId) 
    ,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP) 
    ,cteR2 as (Select A.JCId,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.JCId) 
Select A.R1 
     ,B.R2 
     ,A.JCId 
     ,A.JCParentId 
     ,A.Lvl 
     ,JCName = Replicate(@Nest,A.Lvl-1) + A.JCName 
From cteR1 A 
Join cteR2 B on A.JCId=B.JCId 
and R1=R2 

Возвращает

enter image description here


Полная Иерархия, когда @top = NULL, и вы удалить конечный и R1 = R2

enter image description here

+0

Это просто сказочный ответ Джон. Но я беспокоюсь о тех людях, которые до сих пор проголосовали за мой вопрос, так как это было очень сложно для меня реализовать. –

+0

@CharanGhate. Ваш вопрос не просил об этом в его первой версии, теперь он совершенно другой. – DavidG

1

Существует много способов. Вот 1.

select whatever 
from table t1 left join table t2 on jcid = jcparentid 
where t2.jcid is null 
+0

Использование 't1' и' t2' действительно не поможет здесь, если вы явно не указали, что это та же таблица с псевдонимом. – DavidG

+0

Как я уже говорил, я хочу получить только те записи из таблицы JobCollection, JCId которой не является родителем каких-либо дальнейших записей И чей Super Parent JCId равен 1. –

0

Я дам ему попробовать:

SELECT JcId FROM JobCollection 
WHERE JcId NOT IN (SELECT JcParentId FROM JobCollection) 

UPDATE: Выберите только тогда, когда JcParentId = 1

SELECT JcId FROM JobCollection 
WHERE JcId NOT IN (SELECT JcParentId FROM JobCollection) 
AND JcParentId = 1 
+0

Логически звучит, но 'not in' имеет тенденцию быть медленным. –

+0

Правда, но он дает желаемый результат. Как вы сказали ... есть много способов сделать это :-) – Svekke

+0

@Svekke Где добавить условие JCId = 1, поскольку я хочу только те записи, чей супер родительский JCId равен 1 –

1

Используя рекурсивную КТР, чтобы получить все потомкам одного JCId, выбрав те, которые не имеют своих детей с помощью not exists(): установка

declare @ParentId int; 
set @ParentId = 1; 

with cte as (
    select JCId, JCName, JCParentId, JCParentName 
    from JobCollection 
    where JCId = @ParentId 
    union all 
    select c.JCId, c.JCName, c.JCParentId, c.JCParentName 
    from JobCollection c 
     inner join cte p on p.JCId = c.JCParentId 
) 
select JCId, JCName, JCParentId, JCParentName 
from cte as o 
where not exists (
    select 1 
    from cte as i 
    where o.JCid = i.JCParentId 
); 

тест: http://rextester.com/LGEQD6195

create table JobCollection (
    JCId int 
    , JCName varchar(50) 
    , JCParentId int 
    , JCParentName varchar(50) 
); 

insert into JobCollection values 
(1, 'A' , null, null) 
,(2, 'B' , null, null) 
,(3, 'A1' , 1, null) 
,(4, 'A2' , 1, null) 
,(5, 'A3' , 1, null) 
,(6, 'B1' , 2, null) 
,(7, 'B2' , 2, null) 
,(8, 'A11', 3, null) 
,(9, 'A12', 3, null) 
,(10, 'A21', 4, null) 
,(11, 'A31', 5, null) 
,(12, 'A32', 5, null) 
,(13, 'B11', 6, null) 
,(14, 'B12', 6, null) 
,(15, 'B21', 7, null) 
,(16, 'B22', 7, null); 

запрос :

declare @ParentId int; 
set @ParentId = 1; 

with cte as (
    select JCId, JCName, JCParentId, JCParentName 
    from JobCollection 
    where JCId = @ParentId 
    union all 
    select c.JCId, c.JCName, c.JCParentId, JCParentName = p.JCName 
    from JobCollection c 
     inner join cte p on p.JCId = c.JCParentId 
) 
select JCId, JCName, JCParentId, JCParentName 
from cte as o 
where not exists (
    select 1 
    from cte as i 
    where o.JCid = i.JCParentId 
); 

Результаты:

+------+--------+------------+--------------+ 
| JCId | JCName | JCParentId | JCParentName | 
+------+--------+------------+--------------+ 
| 11 | A31 |   5 | A3   | 
| 12 | A32 |   5 | A3   | 
| 10 | A21 |   4 | A2   | 
| 8 | A11 |   3 | A1   | 
| 9 | A12 |   3 | A1   | 
+------+--------+------------+--------------+ 
0

Это должно сработать!

SELECT distinct J1.* 
from JobCollection J1 
LEFT JOIN JobCollection J2 ON J1.JCId = J2.JcParentId 
WHERE J2.JcParentId IS NULL 
Смежные вопросы