Несколько STRING_AGG в нескольких столбцах соединения вызывают раздутую агрегацию - PullRequest
0 голосов
/ 01 октября 2019

У меня есть таблица на моем MSSQL-сервере, давайте назовем ее blogPost. У меня также есть две таблицы тегов, давайте назовем их fooTag и barTag. Таблицы тегов используются для тегирования таблицы 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 |
+--------+--------------+

Я хочу получить один блог вместе со всеми его тегами в одной строке, поэтому STRING_AGG() кажется подходящим для выполнения запроса, подобного этому:

SELECT blogPost.*, STRING_AGG(fooTag.tagName, ';') as [fooTags], STRING_AGG(barTag.tagName, ';') as [barTags]
FROM blogPost
LEFT JOIN fooTag ON blogPost.postId = fooTag.postId
LEFT JOIN barTag ON blogPost.postId = barTag.postId
WHERE postId = 1
GROUP BY blogPost.postId, title, body

При созданииэтот запрос я бы ожидал получить результат

| postId | title               |        body | fooTags                 | barTags                 |
+--------+---------------------+-------------+-------------------------+-------------------------+
| 1      | The life on a query | lorem ipsum | sql;query;select-query | sql;query;select-query |
+--------+---------------------+-------------+-------------------------+-------------------------+

Но вместо этого я получаю этот результат, где тэги бара (т.е. последний выбранный 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 |
+--------+---------------------+-------------+-------------------------+-----------------------------------------------+

ПомещениеbarTags последний в операторе SELECT делает так, что barTags получает дубликаты вместо fooTags. Количество созданных дубликатов, по-видимому, связано с количеством столбцов строк, которые агрегируются вместе в первом столбце результата STRING_AGG, поэтому, если fooTags имеет 5 строк для агрегации вместе, будет 5 дубликатов каждого barTag вbarTags столбец в результате.

Как получить желаемый результат без дубликатов?

Ответы [ 2 ]

2 голосов
/ 01 октября 2019

Ваша проблема вызвана тем, что каждая строка в fooTags создает столько строк barTags в JOIN, что приводит к дублированию. Вы можете обойти эту проблему, выполнив STRING_AGG в таблицах footags и bartags до 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
1 голос
/ 01 октября 2019

Вы можете упростить запрос следующим образом:

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

Не требуется GROUP BY, в вашем случае это будет дорогая операция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...