MSSQL以递归方式选择所有相关行

时间:2015-05-04 11:35:32

标签: sql sql-server-2008 recursive-query

我有一个定义/字段关系的层次结构,分布在3个表中:

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深),所以如果你有一个Grand Parent>父母>子层次结构,Child将在Grand Parent / Parent上定义所有属性。

我已经非常接近,但是当Child没有任何属性时会出现问题,它会被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

1 个答案:

答案 0 :(得分: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,在递归期间测试父关系;最初这是孩子的身份