我的老板给了我一张桌子。
Related_Items_Table Item | Accessory --------------------- TV | Antennae TV | Power Cord TV | Remote Laptop | Power Cord Laptop | Carrying Case Camera | Carrying Case Camera | Lens iPod | Headphones
描述我的老板想要结果的最佳方式是完成整个过程。
用户搜索电视。
找到电视,电视配件是Antennae,Power Cord& 远程。
配件Antennae,Power Cord&远程现在用于查找 其他相关项目。电源线也是笔记本电脑的配件。 天线&遥控器不是任何其他物品的附件。
项目笔记本电脑现在用于查找该项目的配件,其中 是电源线和电源线。携带箱。
配件电源线&携带箱现在用于寻找 其他相关项目。电源线找不到新物品(我们已经知道了 电源线与电视和电视有关。笔记本电脑)。携带箱也是 相机配件。
项目相机现在用于查找该项目的附件,其中 是携带箱&透镜。
配件携带箱&镜头现在用于寻找其他镜头 相关项目。携带箱&镜头找不到新物品(我们已经 知道便携包与笔记本电脑有关。
未找到任何新项目以继续搜索链。最终名单 返回。
Final List Item | Accessory --------------------- TV | Antennae TV | Power Cord TV | Remote Laptop | Power Cord Laptop | Carrying Case Camera | Carrying Case Camera | Lens
处理此问题的最佳方法是什么?我不确定这个术语的正确性是什么,所以也许我在搜索中错过了它。任何建议都表示赞赏。
答案 0 :(得分:1)
答案 1 :(得分:0)
我会做这样的pesudocode:
insert into Final_List
all the records that match the item in Related_Items_Table
WHILE 1=1
BEGIN
Insert into Final List
select NextLevel.*
from Related_Items_Table
join Related_Items_Table NextLevel
on Related_Items_Table.Accessory = NextLevel.Item
where the nextlevel.item and nextlevel.accesory not already in Final List
if @@Rowcount = 0
break
END
答案 2 :(得分:0)
-- The sample data from the problem.
declare @SearchString varchar(32) = 'TV';
declare @RelatedItemsTable table
(
[Item] varchar(32),
[Accessory] varchar(32)
);
insert @RelatedItemsTable values
('TV', 'Antennae'),
('TV', 'Power Cord'),
('TV', 'Remote'),
('Laptop', 'Power Cord'),
('Laptop', 'Carrying Case'),
('Camera', 'Carrying Case'),
('Camera', 'Lens'),
('iPod', 'Headphones');
-- This table will hold your results.
declare @SearchResults table
(
[Item] varchar(32),
[Accessory] varchar(32)
);
-- Base case: look for any item or accessory that matches the search string.
-- I'm not sure whether you want to search items only or accessories also;
-- adjust as needed.
insert @SearchResults
select *
from
@RelatedItemsTable
where
[Item] like @SearchString or
[Accessory] like @SearchString;
while @@rowcount > 0
begin
-- The recursive case: look for new records where...
insert @SearchResults
select
[New].[Item],
[New].[Accessory]
from
@RelatedItemsTable [New]
inner join @SearchResults [Old] on
-- ... the new record is an item using the same kind of accessory as
-- an existing item, or...
[New].[Accessory] = [Old].[Accessory] or
-- ... the new record is an accessory for the same kind of item as an
-- existing accessory, and...
[New].[Item] = [Old].[Item]
where
-- ... this record doesn't yet appear in the result set.
not exists
(
select 1
from
@SearchResults [Existing]
where
[Existing].[Accessory] = [New].[Accessory] and
[Existing].[Item] = [New].[Item]
);
end;
select * from @SearchResults;
SQL Server确实有一种递归查询机制 - recursive CTE - 但我无法使用其中一种实现此示例,因为我无法实现上述NOT EXISTS
部分查询。
答案 3 :(得分:0)
我不能像我说的那样用CTE做到这一点。这里解释了原因:Prevent recursive CTE visiting nodes multiple times
所以这是一种古老的时尚方式
DECLARE @MyTable TABLE(Item NVARCHAR(50), Accessory NVARCHAR(50))
DECLARE @Result TABLE(Item NVARCHAR(50), Accessory NVARCHAR(50), LinkedItem NVARCHAR(50), Done int)
INSERT INTO @MyTable
VALUES
('TV', 'Antennae'),
('TV', 'Power Cord'),
('TV', 'Remote'),
('Laptop', 'Power Cord'),
('Laptop', 'Carrying Case'),
('Camera', 'Carrying Case'),
('Camera', 'Lens')
DECLARE @NbIteration INT = 0
INSERT INTO @Result
SELECT t.Item,
t.Accessory,
LinkedItem.Item,
@NbIteration
FROM @MyTable AS t
LEFT JOIN @MyTable AS LinkedItem ON t.Accessory = LinkedItem.Accessory
WHERE t.Item = 'TV'
WHILE(@@ROWCOUNT > 0)
BEGIN
SELECT @NbIteration = @NbIteration + 1
INSERT INTO @Result
SELECT t.Item,
t.Accessory,
LinkedItem.Item,
@NbIteration
FROM @Result AS r
INNER JOIN @MyTable AS t ON r.LinkedItem = t.Item
LEFT JOIN @MyTable AS LinkedItem ON t.Accessory = LinkedItem.Accessory
WHERE r.Done = @NbIteration - 1
AND NOT EXISTS(SELECT TOP 1 1 FROM @Result AS Sub WHERE t.Item = Sub.Item) --don't go back to records already done
END
SELECT DISTINCT Item, Accessory
FROM @Result
答案 4 :(得分:0)
如果您不反对使用GOTO语句进行循环,那么您可以尝试实现,这是一个解决方案:
DECLARE @search VARCHAR(50) = 'TV'
--Get initial resultset
DECLARE @table TABLE (item VARCHAR(50), accessory VARCHAR(50))
INSERT INTO @table
SELECT
items.*
FROM
items
WHERE
item LIKE @search
--declare the variables used for checking if we have any new results
DECLARE @intCount INT = (SELECT COUNT(*) FROM @table)
DECLARE @intNewCount INT = (SELECT COUNT(*) FROM @table)
--The infamous GOTO label
START:
--Store the count of items
SET @intCount = (SELECT COUNT(*) FROM @table)
--Insert any matching rows for accessory = accessory, excluding ones already added
INSERT INTO @table
(item, accessory)
SELECT
item, accessory
FROM
items
WHERE
accessory IN (SELECT accessory FROM @table)
AND NOT EXISTS(SELECT TOP 1 1 FROM @table t WHERE t.item = items.item AND t.accessory = items.accessory)
--Now Insert any matching rows for item = item, excluding ones already added
INSERT INTO @table
(item, accessory)
SELECT
item, accessory
FROM
items
WHERE
item IN (SELECT item FROM @table)
AND NOT EXISTS(SELECT TOP 1 1 FROM @table t WHERE t.item = items.item AND t.accessory = items.accessory)
--Set the new count
SET @intNewCount = (SELECT COUNT(*) FROM @table)
--Check if there's been any added during this iteration, if there are, repeat!
IF @intCount <> @intNewCount GOTO START;
--Finished
SELECT * FROM @table
我看到大多数其他答案都有一个while循环,我想我只是把它混合起来:)在SQL2008中测试