在 SELECT 期间用 JOIN 操作替换子记录列
Posted
技术标签:
【中文标题】在 SELECT 期间用 JOIN 操作替换子记录列【英文标题】:Replacing child record columns during SELECT with JOIN operation 【发布时间】:2015-09-02 09:50:09 【问题描述】:我正在尝试通过将两个表连接在一起来创建一个视图,这绝不是困难的。但是有一个但是。
我基本上有两张桌子。其中一个存储项目和标签之间的关联,另一个以父子形式存储标签(8 个父母,每个父母有 4-6 个孩子)。
请允许我从我的项目关联表开始说明:
AssociationId | ItemId | TagId
------------------------------
1 | 2 | 1
2 | 10 | 2
3 | 3 | 1
4 | 5 | 7
...
还有我的标签表:
TagId | ParentId | Name
------------------------------
1 | NULL | abc sds
2 | 1 | sjdksd as
3 | 1 | djfsd dfs d
4 | NULL | ujkjsd as
...
如您所见,可以通过使用ParentId IS NULL
装饰查询来找到每个父级。
SELECT ITA.AssociationId, ITA.ItemId, ITA.TagId, T.Name as TagName
FROM Item_Tag_Association AS ITA
INNER JOIN Tags AS T
ON T.TagId = ITA.TagId
WHERE T.ParentId IS NULL
如果我要将TagId
和ParentId IS NULL
上的两个表连接起来,我会找到所有带有父标签的项目。
如果我要将TagId
上的两个表与ParentId IS NOT NULL
连接起来,我会找到所有带有子标签的项目。
但我真正想要的是一个项目和标签列表,其中子标签被它们的父标签替换。
使用上面的示例,结果将如下所示:
AssociationId | ItemId | TagId | TagName
----------------------------------------
1 | 2 | 1 | abc sds
2 | 10 | 1 | abc sds
3 | 3 | 1 | abc sds
4 | 5 | 7 | ysdasjdhas
...
至于我想这样做的原因是,我可以计算特定父标签(或该父标签的子标签)与项目相关联的次数。正如您现在所猜到的那样,每个孩子都应该为其父母做出贡献。
SELECT DISTINCT ItemId, TagId, TagName, COUNT(ItemId) OVER (PARTITION BY TagId) AS Count
FROM vw_My_View
ORDER BY Count DESC
我正在使用 SQL Server 2008 R2。欢迎所有建设性的建议。
【问题讨论】:
@Tanner 根据我的问题,最后一张表格说明了所需的结果。 好的,我认为这是计数部分之前的中间步骤。 【参考方案1】:只要您的父/子层次结构中只有一个级别,您就可以从标签到自身进行额外的左连接以找到父级(如果存在的话):
SELECT ita.AssociationId, ita.ItemId, ISNULL(parent.TagId, t.TagId), ISNULL(parent.Name, t.Name) AS TagName
FROM Item_Tags_Association ita
JOIN Tags t ON ita.TagId = t.TagId
LEFT JOIN Tags parent ON t.ParentId = parent.TagId
第一个(内部)连接可以连接到子标签或父标签。左连接将包括父标签 if 关联的标签有父标签。 如果不为空,ISNULL 将确保使用来自第二个(左)连接的值,否则使用来自第一个连接的值。
如果您不想与ISNULL(或COALESCE)打交道,您可以像这样使用UNION 和CTE:
WITH ParentTags AS (SELECT * FROM Tags WHERE ParentId IS NULL)
SELECT ita.AssociationId, ita.ItemId, t.TagId, t.Name AS TagName
FROM ParentTags t
JOIN Item_Tags_Association ita ON ita.TagId = t.TagId
UNION ALL
SELECT ita.AssociationId, ita.ItemId, t.TagId, t.Name AS TagName
FROM ParentTags t
JOIN Tags child ON t.TagId = child.ParentId
JOIN Item_Tags_Association ita ON ita.TagId = child.TagId
【讨论】:
@Iarsts 您认为父/子层次结构只有一个级别是正确的。 我可以确认ISNULL
解决方案正在工作,但我还不明白如何/为什么。但是ISNULL()
的使用还是蛮巧妙的。
尝试在帖子中添加解释。基本上,左连接包含来自父标签的信息 if 它存在(如果关联中的标签定义了 parentid)。 isnull 用于使用来自此父标记的值(如果找到),否则使用来自第一个连接的值(这将是一个没有 parentid -> 的标记,这意味着它是开始的父标记)。这个解释有点繁琐,希望大家理解。
union/cte 方法也应该有效,并且可能更容易阅读:)
@Iarsts union/cte 方法确实更容易阅读,我确认它是一个可行的解决方案。以上是关于在 SELECT 期间用 JOIN 操作替换子记录列的主要内容,如果未能解决你的问题,请参考以下文章
oracle的full join关联的表限制条件在on后面与限制在子查询的结果是不一样