编写SQL查询以从表中获取唯一的超级子记录

编写SQL查询以从表中获取唯一的超级子记录,sql,sql-server,select-query,Sql,Sql Server,Select Query,我正在努力准备一个SQL查询,它应该一次返回预期的数据 我的要求是从名为JobCollection的SQl表中获取数据,该表将返回下图中以绿色边框突出显示的数据 该数据以父子方式组织。 正如你在下面看到的 JCID1是JCID3,4,5的父ID。与JCID2相同的是JCID6,7的ParentID JCId 3、4、5也是8、9、10、11、12等的ParentId 条件: 我只想从JobCollection表中获取那些JCId不是任何其他记录父级的记录 如绿色边框中突出显示的,JCID

我正在努力准备一个SQL查询,它应该一次返回预期的数据

我的要求是从名为JobCollection的SQl表中获取数据,该表将返回下图中以绿色边框突出显示的数据

该数据以父子方式组织。 正如你在下面看到的

  • JCID1是JCID3,4,5的父ID。与JCID2相同的是JCID6,7的ParentID
  • JCId 3、4、5也是8、9、10、11、12等的ParentId
条件:

  • 我只想从JobCollection表中获取那些JCId不是任何其他记录父级的记录
如绿色边框中突出显示的,JCID8、9、10、11和12不是任何记录的父项

绿色边框还突出显示JCID1的超级子级,而不是JCID2

请注意,这是一个示例,我们不能使用存储过程或游标。并且层次结构级别未定义。它可以是任何东西

更新:

再举一个例子

我只想得到那些以红色突出显示的记录。如您所见,绿色边框表示这些是每条记录的超级子记录,但红色突出显示了JCID1的超级子记录

发自内心地,我要求每个人在投票否决这个问题之前,请仔细阅读这个问题并理解其中的痛苦。我真的很难得到预期的结果


有很多方法。这是1

 select whatever
 from table t1 left join table t2 on jcid = jcparentid
 where t2.jcid is null
我来试试:

SELECT JcId FROM JobCollection
WHERE JcId NOT IN (SELECT JcParentId FROM JobCollection)
更新:仅当JcParentId=1时选择

SELECT JcId FROM JobCollection
WHERE JcId NOT IN (SELECT JcParentId FROM JobCollection)
AND JcParentId = 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
Declare@YourTable表(JCId int、JCParentId int、JCName varchar(50))
在@YourTable值中插入
(1,NULL,'A')
,(2,空,'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')

声明@Top int=1--null--使用递归cte获取一个
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, 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           |
+------+--------+------------+--------------+
这应该管用

SELECT  distinct J1.* 
from  JobCollection J1
LEFT JOIN  JobCollection J2 ON J1.JCId = J2.JcParentId
WHERE  J2.JcParentId IS NULL

逻辑上合理,但
不在
中往往较慢。正确,但它给出了所需的结果。正如您所说……有很多方法可以做到这一点:-)@Svekke我在哪里添加一个JCId=1条件,因为我只需要超级父JCId为的记录1@Svekke通过准备我提供的数据,尝试自己运行更新后的查询,因为它在我的数据上为我提供空结果。该查询仅限于级别1。数据级别可以高达N个数字,除非您明确声明它是具有别名的同一个表,否则使用
t1
t2
在这里真的没有帮助。正如我提到的,我只想从JobCollection表中获取那些JCId不是任何其他记录的父级且其超级父级JCId为1的记录。这是一个极好的答案厕所。但我担心那些否决我的问题的人,因为这对我来说真的很难回答implement@CharanGhate你的问题在它的第一个版本中没有提出这个问题,现在完全不同了。
+------+--------+------------+--------------+
| JCId | JCName | JCParentId | JCParentName |
+------+--------+------------+--------------+
|   11 | A31    |          5 | A3           |
|   12 | A32    |          5 | A3           |
|   10 | A21    |          4 | A2           |
|    8 | A11    |          3 | A1           |
|    9 | A12    |          3 | A1           |
+------+--------+------------+--------------+
SELECT  distinct J1.* 
from  JobCollection J1
LEFT JOIN  JobCollection J2 ON J1.JCId = J2.JcParentId
WHERE  J2.JcParentId IS NULL