Объединение групповых строк: какой подход, если таковой вообще существует, гарантирован? - PullRequest
4 голосов
/ 16 февраля 2012

Ицик Бен-Ган объясняет в своей книге «Внутри Microsoft® SQL Server® 2008: T-SQL», как работает Appoach A из-за недокументированного поведения SQL Server, в котором он выполняет назначение для каждого запись результата из SELECT.

Хорошо уважаемый коллега и гуру DB предположили, что Подход B гарантированно работает . Его аргумент основан на рекурсивной природе COALESCE по сравнению с методом «расширения значений» CAST.

На самом деле, я понятия не имею, к чему относится «расширение значений» (за исключением того факта, что оно приводит одно значение к другому) или как оно относится к этой проблеме? Возможно, он неправильно понял? Да COALESCE является в некотором смысле рекурсивным, но, насколько я вижу, это не имеет значения, и желаемый результат получается из-за недокументированного поведения множественного присваивания.

Он прав? Пожалуйста, не используйте "1017 * вместо" ответов!

Подход A

DECLARE @output VARCHAR(100);
SET @output = ''; 

SELECT @output = @output + CAST(COL_VCHAR AS VARCHAR(10)) + ';' 
FROM someTable;

Подход B

DECLARE @output VARCHAR(100);
SELECT @output = COALESCE(@output + ', ', '') + COL_VCHAR  
from someTable;

Ответы [ 4 ]

4 голосов
/ 16 февраля 2012

Я считаю, что они оба работают из-за одного и того же базового (и недокументированного) поведения.Я вполне уверен, что если вы возьмете случай, когда Ицик продемонстрировал, что Подход A терпит неудачу, то Подход B также потерпит неудачу таким же образом и по тем же причинам, несмотря напретензии вашего коллеги.Я не понимаю, как

DECLARE @output VARCHAR(100);
SELECT @output = COALESCE(@output + ', ', '') + COL_VCHAR

отличается от:

DECLARE @output VARCHAR(100) = '';
SELECT @output = @output + ', ' + COL_VCHAR
-- or SELECT @output += ',' + COL_VCHAR

Так что же магически вводит COALESCE?SQL Server не собирается менять свой план из-за того, что вы делаете с выводом, AFAIK.

Я использую их все время для динамической генерации SQL, и не помню, чтобы когда-либо видел, что они терпят неудачу, иЯ понимаю, что это не твой вопрос.К сожалению, на самом деле не существует способа доказать это, если вы не знаете случая, который не подходит ни для одного из подходов.

Я написал сообщение в блоге о конкатенации строк несколько месяцев назад.Это не совсем относится к вашей проблеме, но Роб Фарли сделал комментарий, который можно считать еще одним недостатком подхода COALESCE:

https://sqlblog.org/2011/03/08/t-sql-tuesday-16-this-is-not-the-aggregate-youre-looking-for

2 голосов
/ 17 февраля 2012

Поскольку соответствующая реализация SQL может оценивать все выходные строки одновременно, параллельно, не гарантируется для работы.То, что они случаются на работе, сегодня является артефактом текущей реализации SQL Server.

Ваш коллега неверно утверждает, что COALESCE каким-то образом меняет модель обработки.

Т.е. соответствующая реализация могла бы эффективно передать каждую потенциальную строку в наборе результатов (оценив FROM и WHERE) отдельному потоку, который затем выполняет любую обработку, требуемую в предложении SELECT (до предположительно рекомбинирования результатовдля оценки GROUP BY, HAVING и ORDER BY).

Стандартных требований, регулирующих доступ к переменным во время такой обработки, не существует, поэтому каждый поток может «видеть» одно и то же начальное значение * 1018.* (NULL или '', в зависимости от того, какую форму вы используете), выполните свой собственный расчет обновления и присвойте это значение результата @output - итоговое значение @output может затем соответствовать любой отдельной строкерезультаты - или что-нибудь еще в этом отношении.

0 голосов
/ 17 февраля 2012

Они работают по-разному, первый пример добавляет дополнительный символ в конец выходной переменной, и да, они работают из-за того же поведения.

Первый пример будет работать, если в вашем столбце также была цифра или дата. Однако это займет только первые 10 символов любого значения в столбце. Второй пример не будет отрезать столбец.

Нет абсолютно никакой рекурсивной природы COALESCE. COALESCE - это способ замены нулевых значений заменяющими значениями.

EDIT:

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

0 голосов
/ 17 февраля 2012

В вашем примере есть способ получить разные результаты, и это если значения NULL вводятся в набор данных.Например:

set nocount on

declare @test table (value int)

insert into @test values (10)
insert into @test values (20)
insert into @test values (null)
insert into @test values (40)
insert into @test values (50)

DECLARE @output VARCHAR(max);

-- Approach A
SET @output = ''; 

SELECT @output = @output + CAST(value AS VARCHAR(10)) + ';' 
FROM @test

print 'Result from A:'
print isnull(@output, '{null}')

-- Approach B
set @output = ''
SELECT @output = COALESCE(@output + ', ', '') + cast(value as varchar(10))
from @test

print 'Result from B:'
print isnull(@output, '{null}')

set nocount off

Подход A вернет ноль, тогда как Подход B вернет 40, 50

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