有人可以帮我解决这个问题吗?

时间:2018-02-07 23:12:46

标签: sql-server tsql

此表中的每一行都包含一个名为ParentFamilyId的列,该列告诉您任何系列所属的父系列(所有类别系列 - 编号25 - 没有父系列,因此位于层次结构的顶部)。

使用外部联接创建一个链接3个表的查询,如下所示:

Table       Alias
tblFamily   Family
tblFamily   ParentFamily
tblFamily   TopFamily

将计算列添加到查询中,以便显示所有25个familes:

enter image description here

如果以FamilyName顺序显示系列,您应该会看到类似的内容。

这是我到目前为止所做的:

SELECT Family.FamilyName FamilyName,
       CASE WHEN Family.FamilyName = 'All categories' THEN Family.FamilyName 
            ELSE CONCAT(topfamily.FamilyName, '>', Parentfamily.FamilyName, '>', Family.FamilyName) 
       END AS 'Family path'
FROM tblFamily Family
LEFT JOIN tblFamily ParentFamily ON Family.ParentFamilyId = ParentFamily.FamilyID
LEFT JOIN tblFamily TopFamily ON TopFamily.FamilyName = 'All categories'
order by Family.FamilyName

我有正确的结果,但这是最好的方法吗?我很长一段时间都没有接触过开发,所以练习基础知识。

2 个答案:

答案 0 :(得分:1)

  

使用外部联接创建一个链接3个表的查询,如下所示:
  Table Alias
  tblFamily Family
  tblFamily ParentFamily
  tblFamily TopFamily

我会说,除非你的老师打算使用这个例子作为你应该使用递归ctes的原因,这是一个糟糕的家庭作业。 话虽如此,您的查询实际上并不是正确的答案:

SELECT COALESCE(Family.FamilyName, Parentfamily.FamilyName, topfamily.FamilyName) As 'Family Name',
       topfamily.FamilyName + 
       ISNULL('>' + Parentfamily.FamilyName, '') + 
       ISNULL('>' + Family.FamilyName, '') As 'Family path'
FROM tblFamily As TopFamily 
LEFT JOIN tblFamily As ParentFamily ON ParentFamily.ParentFamilyId = TopFamily.FamilyID
LEFT JOIN tblFamily As Family ON Family.ParentFamilyId = ParentFamily.FamilyID
WHERE TopFamily.ParentFamily.ParentFamilyId IS NULL -- So of someone changes the `All categories` text your query will not have to change
order by Family.FamilyName

注意:

  • 您的第一列Family.FamilyName FamilyName,错误,因为Family可能并不总是包含行。另外,always use the as keyword for aliases.
    我的第一列使用COALESCE来获取三个别名的第一个非空值。

  • 您的第二列假设它为1级或3级,但图片显示不是这样。在我的第二列中,我已经利用了+和varchar值之间的null连接运算符给出null的事实,所以如果Family.FamilyName为null ,结果将是topfamily.FamilyName > Parentfamily.FamilyName

  • 外连接中表的顺序至关重要。由于始终会选择TopFamily别名,因此它必须是from子句中的第一个表,后跟ParentFamily别名,最后是Family别名。

  • 表之间的连接总是在右边table.id = left table.parentId

  • 现在,where子句包含一个条件,对于顶级系列,该条件始终为true,即使您有多个或名称更改。

答案 1 :(得分:0)

像@ZLK建议的那样,您可能想尝试递归CTE。这是一个例子。

;WITH
tblFamily
AS
(
    SELECT tbl.* FROM (VALUES
      ( 1, 0, 'All categories')
    , ( 1, 2, 'Something1')
    , ( 1, 3, 'Something2')
    , ( 1, 4, 'Something3')
    , ( 1, 5, 'Something4')
    , ( 1, 6, 'Something5')
    , ( 2, 10, 'Something10')
    , ( 3, 11, 'Something11')
    , ( 4, 12, 'Something12')
    , ( 5, 13, 'Something13')
    , ( 6, 14, 'Something14')
    ) tbl ([ParentFamilyId], [FamilyID], [FamilyName]) 
)
,
tblFamily_relate ([ParentFamilyId], [FamilyID], [FamilyName], [FamilyTree], [FamilyLevel])
AS
(
    SELECT 
          Family.[ParentFamilyId]
        , Family.[FamilyID]
        , Family.[FamilyName]
        , [FamilyTree] = cast(Family.[FamilyName] as varchar(max))
        , [FamilyLevel] = 0
    FROM 
        tblFamily Family
    WHERE 
        Family.[FamilyID] IN(SELECT [ParentFamilyId] FROM tblFamily)
    UNION ALL
    SELECT 
          Family.[ParentFamilyId]
        , Family.[FamilyID]
        , Family.[FamilyName]
        , [FamilyTree] = cast(ParentFamily.[FamilyName] as varchar(max)) + cast(Family.[FamilyName] as varchar(max))  
        , [FamilyLevel] + 1
    FROM 
        tblFamily Family
        INNER JOIN tblFamily_relate ParentFamily  ON Family.ParentFamilyId = ParentFamily .FamilyID
    WHERE 
        Family.[FamilyID] NOT IN(SELECT [ParentFamilyId] FROM tblFamily)
)
SELECT * FROM tblFamily_relate