SQL Server(最终结果)层次结构Map

x33g5p2x  于 2023-01-20  发布在  SQL Server
关注(0)|答案(3)|浏览(164)

SQL Server 2016中,我有一个具有以下链接结构的表:

dbo.项目

| 原始项目|项目ID|
| - ------|- ------|
| 零|七|
| 1个|第二章|
| 零|1个|
| 五个|六个|
| 三个|四个|
| 零|五个|
| 第二章|三个|
重要的是,这个例子是真实的数据的一个平凡化版本,而整齐的升序条目并不存在于真实数据中,我这样做只是为了简化理解。
我构造了一个查询来获取我称为TerminalItemID的内容,在本例中为ItemID 467,并将其填充到临时表**@TerminalItems**中,其结果集如下所示:

@油库项目

| 终端项目ID|
| - ------|
| 四个|
| 六个|
| 七|
我需要的是一个最终的 mapping 表,它看起来像这样(使用上面的例子--注意,它还包含467到它们自身的Map,这是业务逻辑所需要的):

@Map

| 项目ID|终端项目ID|
| - ------|- ------|
| 1个|四个|
| 第二章|四个|
| 三个|四个|
| 四个|四个|
| 五个|六个|
| 六个|六个|
| 七|七|
我需要帮助的是如何建立这个最后的**@Map**表。任何在这个方向的援助是非常感谢!

eyh26e7m

eyh26e7m1#

这应该做到:

with MyTbl as (
    select *
    from (values 
     (NULL, 1 )
    ,(1,    2 )
    ,(2,    3 )
    ,(3,    4 )
    ,(NULL, 5 )
    ,(5,    6 )
    ,(NULL, 7 )
    ) T(OriginalItem,   ItemID)
)
, TerminalItems as (
    /* Find all leaf level items: those not appearing under OriginalItem column */
    select LeafItem=ItemId, ImmediateOriginalItem=M.OriginalItem
    from MyTbl M
    where M.ItemId not in
                    (select distinct OriginalItem
                      from MyTbl AllParn
                      where OriginalItem is not null
                      )
), AllLevels as (
    /* Use a recursive CTE to find and report all parents */
    select ThisItem=LeafItem, ParentItem=ImmediateOriginalItem
    from TerminalItems
    union all
    select ThisItem=AL.ThisItem, M.OriginalItem
    from AllLevels AL
         inner join
         MyTbl M
         on M.ItemId=AL.ParentItem
     )
select ItemId=coalesce(ParentItem,ThisItem), TerminalItemId=ThisItem
from AllLevels
order by 1,2

注意MAXRECURSION设置;默认情况下,SQLServer迭代递归100次;这意味着你的树的深度可以是100,max(终端项目和它的最终原始项目之间的最大节点数)。这可以增加OPTION(MAXRECURSION nnn),其中nnn可以根据需要调整。它也可以通过使用0完全删除,但不推荐这样做,因为你的数据可能会导致无限循环。

oymdgrw7

oymdgrw72#

可以使用递归CTE计算序列中的最后一项。例如:

with
n (orig_id, curr_id, lvl) as (
  select itemid, itemid, 1 from item
 union all
  select n.orig_id, i.itemid, n.lvl + 1
  from n
  join item i on i.originalitem = n.curr_id
)
select *
from (
  select *, row_number() over(partition by orig_id order by lvl desc) as rn from n
) x
where rn = 1

结果:

orig_id  curr_id  lvl  rn 
 -------- -------- ---- -- 
 1        4        4    1  
 2        4        3    1  
 3        4        2    1  
 4        4        1    1  
 5        6        2    1  
 6        6        1    1  
 7        7        1    1

请参见db<>fiddle中的运行示例。

czfnxgou

czfnxgou3#

这是一个典型的间隙和岛问题,也可以在不递归的情况下分三步执行:

  • 在每个分区的开头分配1
  • 计算标志值(在步骤1生成)的运行总和
  • 提取分区上的最大“ItemID”(在步骤2中生成)
WITH cte1 AS (
    SELECT *, CASE WHEN OriginalItem IS NULL THEN 1 ELSE 0 END AS changepartition 
    FROM Item
), cte2 AS (
    SELECT *, SUM(changepartition) OVER(ORDER BY ItemID) AS parts
    FROM cte1
)
SELECT ItemID, MAX(ItemID) OVER(PARTITION BY parts) AS TerminalItemID 
FROM cte2

检查here演示。
假设:您的端子ID项目对应于NULL“OriginalItem”值前面的“ItemID”值。

相关问题