简体   繁体   English

在SQL Server存储过程中的父行下显示子行

[英]Display child rows under parent rows in SQL Server Stored Procedure

There is a table that has information about projects stored in it. 有一个表包含有关存储在其中的项目的信息。 Each Project has an ID Column(FPNNumber) and a Parent ID column. 每个项目都有一个ID列(FPNNumber)和一个父ID列。 If the project has a parent project, the user selects the ID number of the parent project to go in the parent project cell for that row. 如果项目具有父项目,则用户选择要在该行的父项目单元格中转到的父项目的ID号。 If it doesn't have a parent project, the parent project column will have a 0. I've seen some questions on here similar to mine but it looks like they are all using a level column which I don't have or want to use in my query. 如果它没有父项目,那么父项目列将为0.我在这里看到一些与我类似的问题,但看起来它们都使用了我没有或想要的级别列在我的查询中使用。

My stored for getting the data from the database looks like this: 我存储的用于从数据库获取数据的内容如下所示:

SELECT h.[Priority]
  ,h.[FPNNumber]
  ,h.[ProjectName]
  ,sp.SponsorName
  ,pm.ProjectManagerName
  ,o.[OrgName]
  ,HealthID
  ,[StrategicAlignmentID] + [FinancialAlignmentID] + [TechnologyAlignmentID] As ProjectScore
  ,h.[Cost]
  ,h.[Budget]
  ,h.[PercentComplete]
  ,Convert(varchar(10),h.[EstimatedImpDt], 101) As EstimatedImpDt
  ,[EstimatedROI]
  ,h.[ExpectedBenefit]
  ,CONVERT(Decimal(10, 2),((DATEDIFF(day, h.[PaybackPerioddt], GETDATE()))/365.0)) As PaybackPerioddt

FROM [ProjectNew].[Header] h
   join ProjectNew.Sponsor sp ON h.SponsorID = sp.SponsorID
   join ProjectNew.ProjectManager pm ON h.ProjectManagerID = pm.ProjectManagerID
   Join ProjectNew.Organization o ON h.OrgID = o.OrgID
   where StatusID is null or StatusID < 12

One thing I've tried and worked partially but doesn't work quite how I need was 有一件事我尝试过并且部分工作但是我的工作方式并不合适

;WITH Parents
AS(
   SELECT h.[Priority]
  ,h.[FPNNumber]
  ,h.[ProjectName]
  ,sp.SponsorName
  ,pm.ProjectManagerName
  ,o.[OrgName]
  ,HealthID
  ,[StrategicAlignmentID] + [FinancialAlignmentID] + [TechnologyAlignmentID] As ProjectScore
  ,h.[Cost]
  ,h.[Budget]
  ,h.[PercentComplete]
  ,Convert(varchar(10),h.[EstimatedImpDt], 101) As EstimatedImpDt
  ,[EstimatedROI]
  ,h.[ExpectedBenefit]
  ,CONVERT(Decimal(10, 2),((DATEDIFF(day, h.[PaybackPerioddt], GETDATE()))/365.0)) As PaybackPerioddt

FROM [FPN].[ProjectNew].[Header] h
  join ProjectNew.Sponsor sp ON h.SponsorID = sp.SponsorID
  join ProjectNew.ProjectManager pm ON h.ProjectManagerID = pm.ProjectManagerID
  Join ProjectNew.Organization o ON h.OrgID = o.OrgID
  WHERE StatusID is null or StatusID < 12 and h.ParentID = 0
Union All
  SELECT he.[Priority]
  ,he.[FPNNumber]
  ,he.[ProjectName]
  ,sp.SponsorName
  ,pm.ProjectManagerName
  ,o.[OrgName]
  ,he.HealthID
  ,[StrategicAlignmentID] + [FinancialAlignmentID] + [TechnologyAlignmentID] As ProjectScore
  ,he.[Cost]
  ,he.[Budget]
  ,he.[PercentComplete]
  ,Convert(varchar(10),he.[EstimatedImpDt], 101) As EstimatedImpDt
  ,he.[EstimatedROI]
  ,he.[ExpectedBenefit]
  ,CONVERT(Decimal(10, 2),((DATEDIFF(day, he.[PaybackPerioddt], GETDATE()))/365.0)) As PaybackPerioddt

FROM [FPN].[ProjectNew].[Header] he
  join ProjectNew.Sponsor sp ON he.SponsorID = sp.SponsorID
  join ProjectNew.ProjectManager pm ON he.ProjectManagerID = pm.ProjectManagerID
  Join ProjectNew.Organization o ON he.OrgID = o.OrgID
  Join Parents cte on cte.FPNNumber = he.ParentID
WHERE StatusID is null or StatusID < 12
)
Select * from Parents

When I execute that, the results look like this: 当我执行它时,结果如下所示:

 ID | ParentID
----------------
 1  | 0
 2  | 0
 4  | 2
 5  | 2
 3  | 1
 6  | 1
 7  | 1

I need it to look like this: 我需要它看起来像这样:

 ID | ParentID
----------------
 1  | 0
 3  | 1
 6  | 1
 7  | 1
 2  | 0
 4  | 2
 5  | 2

So for the row with ID 2 has the two corresponding child projects under it, but the Child Projects of ID 1 are below that. 因此,ID为2的行下面有两个相应的子项目,但ID 1的子项目低于该项目。

What am I doing wrong? 我究竟做错了什么? Is there a way to get all child projects to display under their parent project? 有没有办法让所有子项目在其父项目下显示? If so, Is there a way to do this, and then when I call that data to the ListView in Visual Studio, have it so if the user clicks a sort button, it doesn't scramble up the child projects? 如果是这样,有没有办法做到这一点,然后当我将这些数据调用到Visual Studio中的ListView时,如果用户单击一个排序按钮,那么它是否会扰乱子项目?

Select * from Parents
ORDER BY
    CASE WHEN ParentId = 0 THEN Id ELSE ParentId END
    ,ID

Interestingly this question still seems to be getting some attention so I will expand on my narrative a little to make it clearer what is happening during recursion. 有趣的是,这个问题似乎仍然得到了一些关注,所以我会稍微扩展我的叙述,以便更清楚地了解递归期间发生的事情。

your anchor table starts out and grabs 2 rows it holds those in memory and then each of those 2 rows are joined to their child rows then in the next iteration those children are then joined to their children. 你的锚表开始并抓取它在内存中保存的2行,然后将这2行中的每一行连接到它们的子行,然后在下一次迭代中将这些子项连接到它们的子节点。 So it traverses the all of the lineages simultaneously not one at a time which is why you get the order which shows that. 所以它同时遍历所有的谱系,而不是一次遍历,这就是为什么你得到显示的顺序。 Level 0 First Then Level 1, 2, etc. 等级0首先然后是等级1,2等。

So if you desire results in a particular order such as parent then children you must tell sql to order them with an order by statement. 因此,如果您希望以特定顺序(例如父级,然后是子级)获得结果,则必须告诉sql使用order by语句对它们进行排序。 In your particular case because of the way you identified and continued your ParentIds during recursion you need to make the Parentless Parent (0) equal to itself and then order by ids. 在您的特定情况下,由于您在递归期间识别并继续使用ParentId的方式,您需要使Parentless Parent(0)等于其自身,然后按ID排序。 This can be done in a case expression as shows above. 这可以在如上所示的案例表达中完成。

If I understand your question, it seems that you want to make sure the hierarchy is in the proper order. 如果我理解您的问题,您似乎希望确保层次结构的顺序正确。

The following is a generic sample use uses a Sequence based on Title in this case, but can be any available field. 以下是一般样本使用在这种情况下使用基于标题的序列,但可以是任何可用字段。

Also, the Range Keys are completely optional. 此外,范围键是完全可选的。 (remove cteR1 and cteR2 if not needed) (如果不需要,删除cteR1和cteR2)

Declare @Table table (ID int,Pt int,Title varchar(50))
Insert into @Table values (0,null,'Tags'),(1,0,'Transportation'),(2,1,'Boats'),(3,1,'Cars'),(4,1,'Planes'),(5,1,'Trains'),(6,0,'Technology'),(7,6,'FTP'),(8,6,'HTTP'),(9,0,'Finance'),(10,9,'FTP'),(11,9,'401K'),(12,2,'Sail'),(13,2,'Powered'),(14,6,'Internet'),(15,6,'Database'),(16,15,'SQL Server'),(17,15,'MySQL'),(18,15,'MS Access')

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

;with cteHB as (
    Select  Seq  = cast(1000+Row_Number() over (Order by Title) as varchar(500))
           ,ID
           ,Pt
           ,Lvl=1
           ,Title 
     From   @Table 
     Where  IsNull(@Top,-1) = case when @Top is null then isnull(Pt,-1) else ID end
     Union  All
     Select Seq  = cast(concat(cteHB.Seq,'.',1000+Row_Number() over (Order by cteCD.Title)) as varchar(500))
           ,cteCD.ID
           ,cteCD.Pt,cteHB.Lvl+1
           ,cteCD.Title 
     From   @Table cteCD 
     Join   cteHB on cteCD.Pt = cteHB.ID)
    ,cteR1 as (Select Seq,ID,R1=Row_Number() over (Order By Seq) From cteHB)
    ,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
Select B.R1  
      ,C.R2
      ,A.ID
      ,A.Pt
      ,A.Lvl
      ,Title = Replicate(@Nest,A.Lvl-1) + A.Title
      ,A.Seq   -- < Included for Illustration
 From cteHB A
 Join cteR1 B on A.ID=B.ID
 Join cteR2 C on A.ID=C.ID
 Order By B.R1

Returns 返回

在此输入图像描述

You can try something similar to the solution provided in the below stack overflow question: 您可以尝试类似于下面的堆栈溢出问题中提供的解决方案:

Query to get parent records with child record, followed by next parent-child records in mysql 查询以获取具有子记录的父记录,然后是mysql中的下一个父子记录

or you can try the below solution. 或者您可以尝试以下解决方案。

I have provided my solution below to get the order you want. 我在下面提供了我的解决方案以获得您想要的订单。 I have used rnk as additional column, which you can ignore in the final result set. 我使用rnk作为附加列,您可以在最终结果集中忽略它。

CREATE TABLE #ParentChild (
    projectId INT
    ,parentProjectId INT
    )

INSERT INTO #ParentChild
VALUES (1,0),(2,0),(3,1),(4,1),(5,1),(6,2),(7,2),(8,2);

SELECT projectid
    ,parentprojectid
    ,row_number() OVER (
        PARTITION BY parentconsider ORDER BY projectid
        ) AS rnk
FROM (
    SELECT projectId
        ,parentProjectId
        ,CASE 
            WHEN parentProjectId = 0
                THEN projectId
            ELSE parentProjectId
            END AS parentconsider
    FROM #ParentChild
    ) AS x

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM