2015-05-04 52 views
3

我有一個橫跨3個表定義傳播/場關係的層次結構:MSSQL遞歸地選擇所有的相關行

CREATE TABLE ProductDefinition 
(
    ProductDefinitionId int, 
    Name nvarchar(10), 
) 

CREATE TABLE ProductDefinitionRelation 
(
    ProductDefinitionId int, 
    ParentProductDefinitionId int 
) 

CREATE TABLE ProductDefinitionField 
(
    ProductDefinitionFieldId int, 
    ProductDefinitionId int, 
    Name nvarchar(10) 
) 

的想法是,這允許CMS的編輯跨共享公共屬性對象,節省管理員管理時間。

該結構來自第三方,因此無法更改,但現在需要選擇所有父級屬性(深度爲n),因此如果您有父級>父級>子級別,子級將具有所有屬性父母/父母。

我已經非常接近了,但問題出現在孩子沒有任何屬性時,它被CTE內的INNER JOIN過濾掉了。

有沒有人知道我在這個例子中如何避免這個Child2仍然需要擁有Grand Parent/Parent的所有道具?

我在這裏已經設置一個小提琴:http://www.sqlfiddle.com/#!6/08dc3/4,但我的代碼如下:

INSERT INTO ProductDefinition 
    VALUES (1,'G. Parent'),(2,'Parent'),(3,'Child1'),(4,'Child2'),(5,'Child3'); 

INSERT INTO ProductDefinitionField 
VALUES 
    (1,1,'G. Field'), 
    (2,2,'P. Field'), 
    (3,3,'C. Field'), 
    (4,5,'C. Field'); 

INSERT INTO ProductDefinitionRelation 
VALUES (2,1),(3,2),(4,2),(5,2); 

WITH Fields 
AS 
    (
     SELECT 
      pd.ProductDefinitionId 
      , pd.Name AS [ProductDefinitionName] 
      , pdf.ProductDefinitionFieldId 
      , pdf.Name AS [ProductDefinitionFieldName] 
     FROM 
      ProductDefinition pd 
       LEFT JOIN ProductDefinitionRelation pdr ON pd.ProductDefinitionId = pdr.ProductDefinitionId 
       LEFT JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId 
     WHERE 
      pdr.ProductDefinitionId IS NULL 

    UNION ALL 

     SELECT 
      pd.ProductDefinitionId 
      , pd.Name AS [ProductDefinitionName] 
      , pdf.ProductDefinitionFieldId 
      , pdf.Name AS [ProductDefinitionFieldName] 
     FROM 
      Fields f 
       JOIN ProductDefinitionRelation pdr ON f.ProductDefinitionId = pdr.ParentProductDefinitionId 
       JOIN ProductDefinition pd ON pdr.ProductDefinitionId = pd.ProductDefinitionId 
       JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId 

    UNION ALL 

     SELECT 
      pd.ProductDefinitionId 
      , pd.Name AS [ProductDefinitionName] 
      , f.ProductDefinitionFieldId 
      , f.ProductDefinitionFieldName AS [ProductDefinitionFieldName] 
     FROM 
      Fields f 
       JOIN ProductDefinitionRelation pdr ON f.ProductDefinitionId = pdr.ParentProductDefinitionId 
       JOIN ProductDefinition pd ON pdr.ProductDefinitionId = pd.ProductDefinitionId 
       JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId 
) 
SELECT DISTINCT 
    * 
FROM 
    Fields 
ORDER BY 
    ProductDefinitionName 

回答

0
WITH FIELDS AS 
    (
     SELECT 
      pd.ProductDefinitionId 
      , pd.ProductDefinitionId [ChildDefinitionID] 
      , pd.Name AS [ProductDefinitionName] 
      , pdf.ProductDefinitionFieldId 
      , pdf.Name AS [ProductDefinitionFieldName] 
     FROM 
      ProductDefinition pd 
      LEFT JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId 

    UNION ALL 

     SELECT 
      f.ProductDefinitionId 
      , pd.ProductDefinitionId [ChildDefinitionID] 
      , f.ProductDefinitionName AS [ProductDefinitionName] 
      , pdf.ProductDefinitionFieldId 
      , pdf.Name AS [ProductDefinitionFieldName] 
     FROM 
      Fields f 
       JOIN ProductDefinitionRelation pdr ON f.ChildDefinitionID = pdr.ProductDefinitionId 
       JOIN ProductDefinition pd ON pdr.ParentProductDefinitionId = pd.ProductDefinitionId        
       JOIN ProductDefinitionField pdf ON pd.ProductDefinitionId = pdf.ProductDefinitionId  
) 
SELECT DISTINCT 
    * 
FROM 
    Fields 
ORDER BY 
    ProductDefinitionName 

http://www.sqlfiddle.com/#!6/89721b/11

理念:
使用兩個領域保持遞歸的軌跡:

  • ProductDefinitionId持有ID字段最終屬於
  • ChildDefinitionID包含孩子的ID,在遞歸期間測試父親關係;最初這是孩子ID
+0

我試過,但這個問題是,你失去了所有的祖父母/父母屬性的孩子。我有一種感覺,解決方案是沿着這些路線,但我會繼續玩。 – Tim

+0

「失去所有祖父母/父母的財產」是什麼意思?如果您正在小提琴中執行查詢,則父/父父母的所有屬性都在那裏。 – flo

+0

如果您將其與我的原始產品進行比較,您會收到: Child1 - C. Field,P. Field和G. 您剛剛返回 Child1 - C.字段 – Tim