将一对一的关系转换为一对多的关系

时间:2018-02-22 13:06:19

标签: sql sql-server tsql

我正在处理包含项目及其详细信息的表格。 该表包含ItemID以及" Alt_ItemID"它存储另一个可用于代替原始Item的ItemID。例如

ItemID,Item_Description,Alt_ItemID

ABC123,Square Brick,ABC456

ABC456,Almost Square Brick,null

因此,如果我们缺货,项目ABC123可以在其中使用项目ABC456。

这些关系可以继续,因此ABC456可以有一个替代的DEF123,可以用来代替ABC123或ABC456。 '级联'可以无限期地继续下去(某些项目的使用优先顺序中列出了20-30种替代方式)

我使用游标(我知道的很慢)循环遍历下面的表并编译一对多(全局,所以我可以看到它有多远)临时表显示&# 34;原"项目和所有可能的级联项目。问题是,目前的速度需要大约10个小时才能完成,所以我们不能在实时报告中使用它(并且由于Items表的流畅性质不适合定期存储)。 / p>

关于使用连接/ CTE的安排是否可以更快地完成任何想法?

NB。 " @AltItem<> @ PART_NUM"和" @AltItem<> ''"不幸的是,由于自我引用的错误数据和级联反应,这是必要的。而烦人的空白。

 create table ##Alternatives (ItemID varchar(50), Alt_ItemID varchar(50))


 Declare @ItemID AS Nvarchar(MAX) 
 DEclare @AltItem as nvarchar(max)



 DECLARE Alternatives CURSOR FOR                
    SELECT ItemID                           
    FROM DatabaseName.dbo.ItemTable             


 OPEN Alternatives                      

 FETCH NEXT FROM Alternatives   
 INTO @ItemID       

 WHILE @@FETCH_STATUS = 0  
 BEGIN  

 select @AltItem = Alt_ItemID from DatabaseName.dbo.ItemTable where ItemID = @ItemID and Alt_ItemID <> @ItemID

                while  @AltItem is not null and @AltItem <> '' and @AltItem <> @ItemID
                 begin
                 insert into ##Alternatives values (@ItemID, Alt_ItemID)
                 select @AltItem = Alt_ItemID from DatabaseName.dbo.ItemTable
                  where ItemID = @AltItem and Alt_ItemID <> @AltItem and Alt_ItemID <> @ItemID

                end  
 FETCH NEXT FROM Alternatives   
 INTO @ItemID  
 END   
 CLOSE Alternatives;  
 DEALLOCATE Alternatives;  


 select * from ##Alternatives
 --drop table ##Alternatives

1 个答案:

答案 0 :(得分:2)

这是使用递归CTE的答案:

<强>设置

CREATE TABLE #ItemTable
(
ItemID varchar(10) PRIMARY KEY, 
Item_Description varchar(50), 
Alt_ItemID varchar(10) NULL
)

INSERT INTO #ItemTable
VALUES ('ABC123', 'Square Brick', 'ABC456'),
        ('ABC456', 'Almost Square Brick', null),
        ('DEF123', 'Sphere', 'GHI789'),
        ('GHI789', 'Oval', 'XYZ123'),
        ('XYZ123', 'Circle', NULL)

公用表表达式查询

WITH CTE
AS
(
    -- Find the top level item
    SELECT ItemId As ParentItemId, ItemId, Item_Description, Alt_ItemId, 0 As Level
    FROM #ItemTable IT1
    WHERE NOT EXISTS (SELECT * FROM #ItemTable IT2 WHERE IT1.ItemID = IT2.Alt_ItemId)
    UNION ALL
    SELECT CTE.ParentItemId As ParentItemId, IT1.ItemId, IT1.Item_Description, IT1.Alt_ItemId, CTE.Level + 1 As Level
    FROM #ItemTable IT1
    INNER JOIN CTE
        ON CTE.Alt_ItemId = IT1.ItemId
)
SELECT ParentItemId, ItemId, Item_Description
FROM CTE
WHERE CTE.LEvel > 0
ORDER By ParentItemId

<强>结果:

ParentItemId    ItemId  Item_Description
------------    ------  -------------------
ABC123          ABC456  Almost Square Brick
DEF123          GHI789  Oval
DEF123          XYZ123  Circle