2010-09-26 75 views
4

我有一個表是這樣的:SQL要獲取父從自參照表

Item 
{ 
    int ItemID 
    int ParentID 
    string Name 
} 

項目實際上是一個更大的表對象的一個​​子集:

Object 
{ 
    int ObjectID 
    string Color 
} 

所以ItemID是一個FK到ObjectID 。在Item之內,ParentID可以引用另一個項目或父對象。

我想要做的就是能夠從項目關係中的葉子一直向上遍歷其父項,直到我終於可以確定給定的項目葉子從哪裏下降到ObjectID

我想在SQL中執行此操作。我正在使用SQL Server 2008.

這是我在想什麼。我可以迭代項目ParentID,直到我不能再與其他項目加入ParentID。這ParentID是我想要返回的ObjectID

我一直試圖讓這個工作使用內部連接,但沒有運氣。我使用C#,所以如果這可以在linq中完成,我不懷疑它可以沒有可怕的低效率,那也可以。

回答我去:

WITH ObjectH (ParentID, ItemID, Level) AS 
(
    -- Base case 
    SELECT 
     ParentID, 
     ItemID, 
     1 as Level 
    FROM Item 
    WHERE ItemID = @param 

    UNION ALL 

    -- Recursive step 
    SELECT 
     i.ParentID, 
     i.ItemID, 
     oh.Level + 1 AS Level 
    FROM Item i 
     INNER JOIN ObjectH oh ON 
     c.ItemID = oh.ParentID   
) 

SELECT TOP 1 ParentID 
FROM ObjectH 
ORDER BY Level DESC 

這工作。

回答

1

我試圖用遞歸SQL Server CTE來做到這一點。從邏輯上講,這就是CTE的工作方式,這應該如此,但是我從來沒有用過與你的模式完全相同的模式。

通常SQL中的樹結構不具有額外的父「對象」表。 (似乎你是模仿你的對象設計完全1:1的數據庫以及?我會重新審視這種模式,如果我是你

試試吧,讓我知道它是否工作。

編輯:改變了基本查詢條件的位

EDIT2:改變了查詢,以使之具體化的一個項目

WITH ObjectHierarchy (ItemID, Name, ParentID, Level) AS 
(
    SELECT 
     ItemID, 
     Name, 
     ParentID, 
     1 as Level 
    FROM Item it, Object ob 
    WHERE it.ParentID = ob.ObjectID 
    AND ob.ItemID = @itemIdToBeSearched 

    UNION ALL 

    SELECT 
     i.ItemID, 
     i.Name, 
     i.ParentID, 
     oh.Level + 1 AS Level 
    FROM Item i 
    INNER JOIN ObjectHierarchy oh ON 
     i.ParentID = oh.ItemID 
    AND oh.ItemID = @itemIdToBeSearched 

) 

SELECT parentID 
FROM ObjectHierarchy 
WHERE LEVEL = 1 
+0

該代碼起作用,因爲它列出了所有關係,但是如何選擇給定任何ItemID的ObjectID? – George 2010-09-26 03:56:15

+0

它現在只是返回一個巨大的ParentID列表。我可以告訴查詢是在做什麼,所以我可能能夠從這裏開始工作。我不是SQL文盲,但我只是不夠好做遞歸的東西。感謝您的編輯! – George 2010-09-26 04:18:22

+0

該列表包含多個Level = 1。它列出了每個可能的Level = 1。我一直在看,並據我所知可以工作。再次感謝 – George 2010-09-26 04:51:01

0

剛剛創建SQL的標量函數迭代的你,並將其包含在模仿你的表的視圖中,但將函數的結果作爲列添加。然後,將您的LINQ對象放在視圖上,並在代碼中擁有ParentID。

1

首先,允許ParentID列引用兩個不同的表作爲「外鍵」是可怕的設計。由於您正在編寫此查詢時遇到困難,您可能已經意識到了這一點。

話雖如此,假設你在一個點,你不能重新設計你的方案,我想辦法通過創建一個代表項目,因爲它「應該」是一個視圖,然後採用傳統的解決這個問題在該視圖上遞歸的CTE方法來遍歷層次結構。

create view vwItem 
as 
select i.ItemID, 
     case when o.ObjectID is null then i.ParentID else null end as ParentID, 
     o.ObjectID, Name 
    from Item i 
     left join Object o 
      on i.ParentID = o.ObjectID 
go 

;with cteItemList as (
    select i.ItemID, i.ParentID, i.ObjectID, i.Name, 1 as Level 
     from vwItem i 
     where i.ParentID is null 
    union all 
    select i.ItemID, i.ParentID, i.ObjectID, i.Name, il.Level+1 as Level 
     from vwItem i 
      inner join cteItemList il 
       on i.ParentID = il.ItemID 
) 
select * 
    from cteItemList 
    order by Level, ItemID 
+0

完全同意你的看法,很高興你認爲CTE是傳統的! – MikeAinOz 2010-09-26 04:21:18