T-SQL CTE获取父项

时间:2018-10-25 13:01:37

标签: sql-server tsql common-table-expression

我已经尝试研究了到目前为止在网站上发布的一些示例,但是在将它们应用于我的问题上似乎没有任何进展。

我有一个包含列表值的表,这些值可以在同一表中具有与之关联的各种父项。不幸的是,这是系统提供的表格,因此我无法对其工作方式进行任何更改。

这是我的表EnumType中的一组数据示例

EnumTypeID     ParentEnumTypeID
1              Null
2              1
3              2
4              3
5              2
6              3
7              1
8              7

我想做的是找到任何子级的最终父级,其中1是最大层次结构值(在系统中,1是根列表,所有值都是1的后代)。 因此,对于任何提供的ID,我应该能够获得指定的最顶层父级,其父级为1(即始终返回第二层,其中enumtypeID的父级= 1)。 例如对于枚举类型6应该返回parentenumtypeid 2,枚举类型8应该返回7等等。 我以前确实有过一些东西,但似乎只返回了下一层而不是根值

WITH cte (enumtypeid, parentenumtypeid) AS
(
SELECT EnumTypeId,ParentEnumTypeId FROM EnumType WITH (NOLOCK)

UNION ALL
SELECT
e.enumtypeid, e.parentenumtypeid
FROM EnumType e
INNER JOIN cte ON cte.parentenumtypeid=e.EnumTypeId
WHERE e.ParentEnumTypeId IS NULL AND e.ParentEnumTypeId != '1'
)

要为此添加更多上下文,这是我完整的SQL。该查询是从我的帮助台数据库中检索一些变更请求详细信息的更广泛查询的一部分

declare @planguagecode nvarchar(3) = 'ENU'
declare @putcoffset int = 1

WITH ChangeEnum (enumtypeid, parentenumtypeid) AS
(
SELECT EnumTypeId,ParentEnumTypeId FROM EnumType WITH (NOLOCK)

UNION ALL
SELECT
e.enumtypeid, e.parentenumtypeid
FROM EnumType e
INNER JOIN ChangeEnum ON ChangeEnum.parentenumtypeid=e.EnumTypeId
WHERE e.ParentEnumTypeId IS NULL AND e.ParentEnumTypeId != '28F88C04-D11D-78C0-A237-FA9ABD6C6478'
)
SELECT DISTINCT
crq.Id_9A505725_E2F2_447F_271B_9B9F4F0D190C as 'id', 
crq.Title_9691DD10_7211_C835_E3E7_6B38AF8B8104 as 'title', 
COALESCE(sds.DisplayName, 'No Status') as 'status', 
COALESCE(cds.DisplayName, 'Uncategorised') as 'category', 
COALESCE(ads.DisplayName, 'Not Assigned') as 'area', 
COALESCE(rds.DisplayName,'Not Assessed') as 'risk', 
COALESCE(pds.DisplayName,'Not Assigned') as 'priority', 
COALESCE(CASE WHEN rads.DisplayName != ads.DisplayName THEN RADS.DisplayName ELSE ADS.Displayname END,'Not Assigned') as 'rootarea',
CONVERT(VARCHAR(16),DATEADD(mi, @pUTCOffset, crq.CreatedDate_6258638D_B885_AB3C_E316_D00782B8F688),120) as 'created',
CONVERT(VARCHAR(16),DATEADD(mi, @pUTCOffset, crq.ScheduledStartDate_89429D01_365C_366D_FCDA_3198102B180C),120) as 'start', 
CONVERT(VARCHAR(16),DATEADD(mi, @pUTCOffset, crq.ScheduledEndDate_6FC72C26_565D_CB2A_BBAF_6A699C15FE99),120) as 'end'
FROM MTV_System$WorkItem$ChangeRequest crq WITH (NOLOCK)
LEFT JOIN DisplayStringView rds WITH (NOLOCK) ON crq.Risk_B9DCB168_B698_6864_E562_08F986C1D4E0 = rds.LTStringId AND rds.LanguageCode = @pLanguageCode
LEFT JOIN DisplayStringView ads WITH (NOLOCK) ON crq.Area_BC1C6C5B_F242_D568_BE10_FC23CD14655A = ads.LTStringId AND ads.LanguageCode = @pLanguageCode
LEFT JOIN DisplayStringView sds WITH (NOLOCK) ON crq.Status_72C1BC70_443C_C96F_A624_A94F1C857138 = sds.LTStringID AND sds.LanguageCode = @pLanguageCode
LEFT JOIN DisplayStringView cds WITH (NOLOCK) ON crq.Category_7B1892FE_108A_EC85_064D_7815C2DFC442 = cds.LTStringID AND cds.LanguageCode = @pLanguageCode
LEFT JOIN DisplayStringView pds WITH (NOLOCK) ON crq.Priority_B1226A17_0705_8F13_1ED4_74A38D2E1707 = pds.LTStringId AND pds.LanguageCode = @pLanguageCode
LEFT JOIN ChangeEnum ce on crq.Area_BC1C6C5B_F242_D568_BE10_FC23CD14655A=ce.enumtypeid
LEFT JOIN DisplayStringView rads WITH (NOLOCK) ON ce.parentenumtypeid = RADS.LTStringId AND RADS.LanguageCode = @pLanguageCode AND RADS.LTStringId ! ='28F88C04-D11D-78C0-A237-FA9ABD6C6478'
WHERE 
    crq.ScheduledStartDate_89429D01_365C_366D_FCDA_3198102B180C IS NOT NULL /* Scheduled */ AND 
    crq.Status_72C1BC70_443C_C96F_A624_A94F1C857138 = '6d6c64dd-07ac-aaf5-f812-6a7cceb5154d' /* In Progress */

因此,总而言之,我需要获取其父ID为1的孩子的最高父ID。在这种情况下,本身没有父项的父1只是表的占位符。子ID由上面的查询从另一个表提供。

2 个答案:

答案 0 :(得分:0)

这适用于所提供的表格示例。我用6进行演示

declare @leaf int = 6

while exists (select * from enums where parentenumtypeid <> 1 and enumtypeid = @leaf)
    select @leaf = parentenumtypeid from enums where enumtypeid = @leaf;
    print @leaf;

编辑

    CREATE FUNCTION FindCustomParent (@input VARCHAR(250))
RETURNS VARCHAR(250)
AS BEGIN
    declare @output int
    set @output = @input

while exists (select * from ChangeEnum where parentenumtypeid <> '28F88C04-D11D-78C0-A237-FA9ABD6C6478' and enumtypeid = @output)
    select @output = parentenumtypeid from ChangeEnum where enumtypeid = @output;
    return @output
END


    SELECT DISTINCT
    crq.Id_9A505725_E2F2_447F_271B_9B9F4F0D190C as 'id', 
    crq.Title_9691DD10_7211_C835_E3E7_6B38AF8B8104 as 'title', 
    COALESCE(sds.DisplayName, 'No Status') as 'status', 
    COALESCE(cds.DisplayName, 'Uncategorised') as 'category', 
    COALESCE(ads.DisplayName, 'Not Assigned') as 'area', 
    COALESCE(rds.DisplayName,'Not Assessed') as 'risk', 
    COALESCE(pds.DisplayName,'Not Assigned') as 'priority', 
    COALESCE(CASE WHEN rads.DisplayName != ads.DisplayName THEN RADS.DisplayName ELSE ADS.Displayname END,'Not Assigned') as 'rootarea',
    CONVERT(VARCHAR(16),DATEADD(mi, @pUTCOffset, crq.CreatedDate_6258638D_B885_AB3C_E316_D00782B8F688),120) as 'created',
    CONVERT(VARCHAR(16),DATEADD(mi, @pUTCOffset, crq.ScheduledStartDate_89429D01_365C_366D_FCDA_3198102B180C),120) as 'start', 
    CONVERT(VARCHAR(16),DATEADD(mi, @pUTCOffset, crq.ScheduledEndDate_6FC72C26_565D_CB2A_BBAF_6A699C15FE99),120) as 'end',

    dbo.FindFirstParent(crq.Area_BC1C6C5B_F242_D568_BE10_FC23CD14655A) as Parent

    FROM MTV_System$WorkItem$ChangeRequest crq WITH (NOLOCK)
    LEFT JOIN DisplayStringView rds WITH (NOLOCK) ON crq.Risk_B9DCB168_B698_6864_E562_08F986C1D4E0 = rds.LTStringId AND rds.LanguageCode = @pLanguageCode
    LEFT JOIN DisplayStringView ads WITH (NOLOCK) ON crq.Area_BC1C6C5B_F242_D568_BE10_FC23CD14655A = ads.LTStringId AND ads.LanguageCode = @pLanguageCode
    LEFT JOIN DisplayStringView sds WITH (NOLOCK) ON crq.Status_72C1BC70_443C_C96F_A624_A94F1C857138 = sds.LTStringID AND sds.LanguageCode = @pLanguageCode
    LEFT JOIN DisplayStringView cds WITH (NOLOCK) ON crq.Category_7B1892FE_108A_EC85_064D_7815C2DFC442 = cds.LTStringID AND cds.LanguageCode = @pLanguageCode
    LEFT JOIN DisplayStringView pds WITH (NOLOCK) ON crq.Priority_B1226A17_0705_8F13_1ED4_74A38D2E1707 = pds.LTStringId AND pds.LanguageCode = @pLanguageCode
    LEFT JOIN ChangeEnum ce on crq.Area_BC1C6C5B_F242_D568_BE10_FC23CD14655A=ce.enumtypeid
    LEFT JOIN DisplayStringView rads WITH (NOLOCK) ON ce.parentenumtypeid = RADS.LTStringId AND RADS.LanguageCode = @pLanguageCode AND RADS.LTStringId ! ='28F88C04-D11D-78C0-A237-FA9ABD6C6478'
    WHERE 
        crq.ScheduledStartDate_89429D01_365C_366D_FCDA_3198102B180C IS NOT NULL /* Scheduled */ AND 
        crq.Status_72C1BC70_443C_C96F_A624_A94F1C857138 = '6d6c64dd-07ac-aaf5-f812-6a7cceb5154d' /* In Progress */

答案 1 :(得分:0)

下面的示例演示了如何使用公用表表达式(CTE)遍历树,同时跟踪根目录下的第一级子级。

-- Sample data.
declare @Enums as Table ( EnumTypeId Int Identity, ParentEnumTypeId Int );
insert into @Enums ( ParentEnumTypeId ) values
  ( NULL ), ( 1 ), ( 2 ), ( 3 ), ( 2 ), ( 3 ), ( 1 ), ( 7 );
select * from @Enums;

-- Walk the tree tracking the parentage.
with
  Enums as (
    -- Start at the roots which have a   NULL   parent.
    select EnumTypeId, ParentEnumTypeId, Cast( NULL as Int ) as PenultimateParentEnumTypeId, 0 as Depth
      from @Enums
      where ParentEnumTypeId is NULL
    union all
    -- Add each level of leaves.
    select CE.EnumTypeId, CE.ParentEnumTypeId,
      -- If the parent has no parent or, equivalently, the parent's depth is zero, then capture the
      --   child's   EnumTypeId .
      case when E.ParentEnumTypeId is NULL then CE.EnumTypeId else PenultimateParentEnumTypeId end,
      -- case when E.Depth = 0 then CE.EnumTypeId else PenultimateParentEnumTypeId end,
      E.Depth + 1
      from Enums as E inner join
        @Enums as CE on CE.ParentEnumTypeId = E.EnumTypeId )
  -- Output the results.
  select EnumTypeId, ParentEnumTypeId, PenultimateParentEnumTypeId, Depth
    from Enums
    order by EnumTypeId;
相关问题