多个连接列上的多个 STRING_AGG 会导致聚合膨胀

Han*_*mer 5 sql sql-server group-by aggregate-functions

我的 MSSQL 服务器中有一个表,我们称之为blogPost。我还有两个标签表,我们称它们为fooTagbarTag。标记表用于标记blogPost结构相同的表。

blogPost

| postId | title               |        body |
+--------+---------------------+-------------+
| 1      | The life on a query | lorem ipsum |
+--------+---------------------+-------------+

fooTag and barTag

| postId | tagName      |
+--------+--------------+
| 1      | sql          |
| 1      | query        |
| 1      | select-query |
+--------+--------------+

Run Code Online (Sandbox Code Playgroud)

我想在一行中获取一篇博文及其所有标签,因此STRING_AGG()适合进行如下查询:

blogPost

| postId | title               |        body |
+--------+---------------------+-------------+
| 1      | The life on a query | lorem ipsum |
+--------+---------------------+-------------+

fooTag and barTag

| postId | tagName      |
+--------+--------------+
| 1      | sql          |
| 1      | query        |
| 1      | select-query |
+--------+--------------+

Run Code Online (Sandbox Code Playgroud)

进行此查询时,我希望得到结果

| postId | title               |        body | fooTags                 | barTags                 |
+--------+---------------------+-------------+-------------------------+-------------------------+
| 1      | The life on a query | lorem ipsum | sql;query;select-query | sql;query;select-query |
+--------+---------------------+-------------+-------------------------+-------------------------+
Run Code Online (Sandbox Code Playgroud)

但我得到的结果是条形标签(即最后选择的 STRING_AGG)重复的结果。

| postId | title               |        body | fooTags                 | barTags                                       |
+--------+---------------------+-------------+-------------------------+-----------------------------------------------+
| 1      | The life on a query | lorem ipsum | sql;query;select-query; | sql;sql;sql;query;query;query;select-query;select-query;select-query |
+--------+---------------------+-------------+-------------------------+-----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

barTags最后放在 SELECT 语句中可以barTags获取重复项而不是fooTags. 创建的重复项数量似乎与第一个结果列中聚合在一起的行列数量相关STRING_AGG,因此如果有 5 行聚合在一起,则结果列中的fooTags每行将有 5 个重复项。barTagbarTags

我怎样才能得到我想要的结果而不重复?

Nic*_*ick 8

您的问题是由在 中fooTags创建那么多行的每一行引起的,因此是重复的。您可以通过在和表之前执行 来解决此问题:barTagsJOINSTRING_AGGfootagsbartags JOIN

SELECT blogPost.*, f.tags as [fooTags], b.tags as [barTags]
FROM blogPost
LEFT JOIN (SELECT postId, STRING_AGG(tagName, ';') AS tags
           FROM fooTag
           GROUP BY postId) f ON blogPost.postId = f.postId
LEFT JOIN (SELECT postId, STRING_AGG(tagName, ';') AS tags
           FROM barTag
           GROUP BY postId) b ON blogPost.postId = b.postId
WHERE postId = 1
Run Code Online (Sandbox Code Playgroud)


Sal*_*n A 5

您可以像这样简化查询:

SELECT blogPost.*, ca1.*, ca2.*
FROM blogPost
OUTER APPLY (
    SELECT STRING_AGG(tagName, ';')
    FROM fooTag
    WHERE blogPost.postId = fooTag.postId
) AS ca1(fooTags)
OUTER APPLY (
    SELECT STRING_AGG(tagName, ';')
    FROM barTag
    WHERE blogPost.postId = barTag.postId
) AS ca2(barTags)
WHERE postId = 1
Run Code Online (Sandbox Code Playgroud)

不需要 GROUP BY,在您的情况下,这将是一个昂贵的操作。