2017-05-10 52 views
1

过去两周,我一直试图弄清楚(非常缓慢)如何提出一种更好的方式来查询所有相关行的ID。我的公司处于一种情况,一个品牌不断被重命名,我们没有修改以前的记录(在其他一些表格中)的选项,指向被替换的品牌。SQL获取所有相关行

我做了我的桌子的小,小的版本,以帮助邀请人们来检查:

CREATE TABLE #GrwHist 
(
    ID INT 
    , Acronym VARCHAR(50) 
    , New_ID INT 
) 

INSERT INTO #GrwHist VALUES(1,'ABC',33) 
INSERT INTO #GrwHist VALUES(21,'GST',NULL) 
INSERT INTO #GrwHist VALUES(33,'MnY',48) 
INSERT INTO #GrwHist VALUES(37,'FWR',89) 
INSERT INTO #GrwHist VALUES(48,'DMZ',89) 
INSERT INTO #GrwHist VALUES(89,'PLT',106) 
INSERT INTO #GrwHist VALUES(106,'TnI',NULL) 
INSERT INTO #GrwHist VALUES(120,'YIZ',143) 
INSERT INTO #GrwHist VALUES(143,'INZ',NULL) 

SELECT * FROM #GrwHist 
/* 
ID Acronym New_ID 
--- ------- ------- 
1 ABC  33 
21 GST  NULL 
33 MnY  48 
37 FWR  89 
48 DMZ  89 
89 PLT  106 
106 TnI  NULL 
120 YIZ  143 
143 INZ  NULL 
*/ 

DECLARE @ID INT 
SET @ID = 106 

SELECT * FROM #GrwHist WHERE ID = @ID 
UNION 
SELECT * FROM #GrwHist WHERE New_ID in (@ID) 
UNION 
SELECT * FROM #GrwHist WHERE New_ID in (SELECT ID FROM #GrwHist WHERE New_ID in (@ID)) 
UNION 
SELECT * FROM #GrwHist WHERE New_ID in (
    SELECT ID FROM #GrwHist WHERE New_ID in (SELECT ID FROM #GrwHist WHERE New_ID in (@ID)) 
) 
UNION 
SELECT * FROM #GrwHist WHERE New_ID in (
    SELECT ID FROM #GrwHist WHERE New_ID in (SELECT ID FROM #GrwHist WHERE New_ID in (SELECT ID FROM #GrwHist WHERE New_ID in (@ID))) 
) 
UNION 
SELECT * FROM #GrwHist WHERE New_ID in (
    SELECT ID FROM #GrwHist WHERE New_ID in (SELECT ID FROM #GrwHist WHERE New_ID in (SELECT ID FROM #GrwHist WHERE New_ID in (SELECT ID FROM #GrwHist WHERE New_ID in (@ID)))) 
) --And it grows and grows... 
GO 
DROP TABLE #GrwHist 

最后查询,基本上是:

--If I need to get all IDs related to a given ID I will get the following results: 
@ID = 106 --> 106, 89, 48, 37, 33, 1 
@ID = 143 --> 143, 120 
@ID = 21 --> 21 

的问题与此查询可能会超过7-8级,而且我想知道是否可以动态执行此操作,以便在每次添加具有关系的另一行时我的代码都需要更改。说如果添加一个新行来替换ID为106的行,我将不得不继续添加。

预先感谢您的任何帮助

回答

1

您可以使用递归CTE获得比赛:

with cte as (
     select id, acronym, null as newid, id as baseid, 1 as lev, 
      cast(id as varchar(max)) as ids 
     from #GrwHist h 
     where newid is null 
     union all 
     select h.id, h.acronym, h.newid, cte.baseid, cte.lev + 1 
      cte.ids + ',' + cast(h.id as varchar(max)) as ids 
     from cte join 
      #GrwHist h 
      on h.new_id = cte.id 
    ) 
select baseid, ids 
from (select cte.*, max(lev) over (partition by baseid) as maxlev 
     from cte 
    ) cte 
where maxlev = lev; 

编辑:

如果有重复的,你可以用获得的每个ID :

select baseid, id 
from cte 
order by baseid; 

在一行上获取值有点复杂。

+0

这是..令人惊叹..它看起来很简单,但我无法理解。但是,它为所有人工作!只有ID 37的那一行没有包含在内。 ID为37的行是两个品牌合并的情况。有没有办法添加它? – Busy

+0

@Busy。 。 。如果它们不是一个简单的链,那么这个逻辑有点复杂。 –

+0

现在我希望我两周前在这里问。我非常努力地想出了自己的想法,因为我害怕有人可能会告诉我,我没有尝试,只是关闭我的线程。所以我一直试图动态SQL等两个星期没有可持续发展。非常感谢;答案接受!你是天赐之物,@GordonLinoff – Busy