stuff () добавляет разделитель, даже если поля пусты - PullRequest
0 голосов
/ 12 октября 2018

Пожалуйста, рассмотрите следующий оператор:

select stuff((
           select '; ' + ([FIELD_1] + [FIELD_2] + [...] + [FIELD_N])
           from   [TABLE] t1
           where  t1.[ID] = t2.[ID]
           for    xml path ('')
        ),1,1, '')
from    [TABLE] t2

Если оператор объединяет 10 записей с одинаковым ID, но все записи не имеют значения ('' или пусто вместо null),вывод:

; ; ; ; ; ; ; ; ; ;

Если заполнены 2 записи, я получаю

; ; ; AAA; ; ; ; BBB;

В этих 2 случаях мне бы хотелось получить null, соответственно AAA; BBB

Я пытался исправить это так:

select stuff((
           select case when [FIELD_1] <> '' then '; ' + ([FIELD_1]) else '' end
           from   [TABLE] t1
           where  t1.[ID] = t2.[ID]
           for    xml path ('')
        ),1,1, '')
from    [TABLE] t2

Это работает и достаточно элегантно для меня, когда я выбираю только FIELD_1.Но когда я выбираю много конкатинированных полей (FIELD_1 + ... + FIELD_N), это становится ужасно быстрым.

Что я делаю не так?Разве stuff() не должен заботиться о моей проблеме как функция?

Ответы [ 2 ]

0 голосов
/ 12 октября 2018

Этот ответ не предназначен для того, чтобы показать лучший способ выполнения запроса - он предназначен для объяснения используемого вами запроса.

Для решения вашей проблемы вы должны использовать выражение where, как показано в примере с белкой его ответ вместо использования выражения case.Нет смысла выбирать вещи, которые вам бесполезны.

Я вижу много путаницы в этом методе агрегирования строк - слишком много людей используют его, не понимая, что делает каждая его часть - так что здесь простоеобъяснение:

Этот метод состоит из трех частей:

  1. агрегирует значения в столбцах.Вот что делает FOR XML PATH('').FOR XML PATH('') вернет строку xml, где теги xml - это имя столбца (или псевдонимы) запроса.(см. столбцы cte_ForXml и Aggregated в примере сценария ниже).

  2. Добавьте разделитель между значениями.Вот что делает ';' +.Он также удаляет теги XML имени столбца из результатов - изменяя имя столбца на пустую строку.Пустые псевдонимы недопустимы в T-SQL, но путем объединения другого значения в столбце имя столбца больше нельзя использовать.
    См. cte_ForXml_WithAnEmptyString и OnlyValuesAggregated в примере сценария.

  3. Удалить лишний разделитель в начале строки.Вот что делает stuff.
    См. cte_FirstDlimiterRemoved и FullQuery в примере сценария.

Что stuff делает, это вставляет строку в другую строку,в указанном index, удаляя length символов из исходной строки.Если вы вставляете пустую строку, вы просто удаляете часть, указанную параметрами index и length из исходной строки.

Пример сценария , чтобы проиллюстрировать различные шагиэтот метод агрегирования строк:

DECLARE @String_Agg AS TABLE 
(
    s varchar(10)
)

INSERT INTO @String_Agg (s) VALUES
('1'), ('2'), ('3')

;WITH cte_ForXml(Aggregated) AS
(
    SELECT s
    FROM @String_Agg
    FOR XML PATH('')
)
, cte_ForXml_WithAnEmptyString(OnlyValuesAggregated) AS
(
    SELECT '' + s
    FROM @String_Agg
    FOR XML PATH('')
) 
, cte_ForXmlWithADelimiter(AggregatedWithADlimiter) AS
(
    SELECT ';' + s
    FROM @String_Agg
    FOR XML PATH('')
), cte_FirstDlimiterRemoved(FullQuery) AS
(
    SELECT STUFF
    (
        (
            SELECT ';' + s
            FROM @String_Agg
            FOR XML PATH('')
        ), 1, 1, ''
    )
)

SELECT Aggregated,  OnlyValuesAggregated, AggregatedWithADlimiter, FullQuery
FROM cte_ForXml
CROSS JOIN cte_ForXml_WithAnEmptyString
CROSS JOIN cte_ForXmlWithADelimiter
CROSS JOIN cte_FirstDlimiterRemoved

Результаты:

Aggregated                  OnlyValuesAggregated    AggregatedWithADlimiter     FullQuery
<s>1</s><s>2</s><s>3</s>    123                     ;1;2;3                      1;2;3
0 голосов
/ 12 октября 2018

добавить условие к предложению WHERE, чтобы исключить строки со всеми значениями пустая строка

select stuff((
           select '; ' + ([FIELD_1] + [FIELD_2] + [...] + [FIELD_N])
           from   [TABLE] t1
           where  t1.[ID] = t2.[ID]
           and    [FIELD_1] + [FIELD_2] + [...] + [FIELD_N] <> ''
           for    xml path ('')
        ),1,1, '')
from    [TABLE] t2
...