Я нахожу способ объединить строки из разных строк в одну. Я хочу сделать это во многих разных местах, поэтому было бы неплохо иметь функцию для облегчения этого. Я пробовал решения с использованием COALESCE
и FOR XML
, но они мне просто не подходят.
Агрегация строк будет делать что-то вроде этого:
id | Name Result: id | Names
-- - ---- -- - -----
1 | Matt 1 | Matt, Rocks
1 | Rocks 2 | Stylus
2 | Stylus
Я рассмотрел агрегатные функции, определенные CLR, как замену COALESCE
и FOR XML
, но, по-видимому, SQL Azure не поддерживает определенные в CLR вещи, что для меня неприятно, потому что я знаю, что возможность его использовать решит множество проблем. проблемы для меня.
Есть ли можно обойти, или так же оптимальный метод (который не может быть оптимальным , так как CLR, но эй , я возьму то , что я могу получить) , что я могу использовать , чтобы объединить свои вещи?
for xml
не работает?for xml
показывает 25% -ное использование с точки зрения производительности запросов (большая часть запроса!)for xml path
запроса. Некоторые быстрее других. Это может зависеть от ваших данных, но те, которые используютdistinct
, по моему опыту, медленнее, чем использованиеgroup by
. И если вы используете.value('.', nvarchar(max))
для получения объединенных значений, вы должны изменить это на.value('./text()[1]', nvarchar(max))
Ответы:
РЕШЕНИЕ
Определение оптимального может варьироваться, но вот как объединить строки из разных строк с помощью обычного Transact SQL, который должен нормально работать в Azure.
ОБЪЯСНЕНИЕ
Подход сводится к трем шагам:
Количество строк , используя
OVER
иPARTITION
группирования и упорядочения их по мере необходимости для конкатенации. Результат -Partitioned
CTE. Мы ведем подсчет строк в каждом разделе, чтобы позже отфильтровать результаты.Используя рекурсивный CTE (
Concatenated
), перебирайте номера строк (NameNumber
столбцов), добавляяName
значения вFullName
столбец.Отфильтруйте все результаты, кроме самых высоких
NameNumber
.Имейте в виду, что для того, чтобы сделать этот запрос предсказуемым, необходимо определить как группировку (например, в вашем сценарии строки с одинаковыми
ID
значениями объединяются), так и сортировку (я предполагал, что вы просто сортируете строку в алфавитном порядке перед объединением).Я быстро протестировал решение на SQL Server 2012 со следующими данными:
Результат запроса:
источник
Действительно ли методы, использующие FOR XML PATH, как показано ниже, настолько медленны? Ицик Бен-Ган пишет, что этот метод имеет хорошую производительность в своей книге запросов T-SQL (на мой взгляд, г-н Бен-Ган является надежным источником).
источник
id
столбец, если размер таблицы станет проблемой.&
переключено на&
и т. Д.). Более правильноеfor xml
решение предоставляется здесь .Для тех из нас, кто нашел это
и не используют базу данных SQL Azure:STRING_AGG()
в PostgreSQL, SQL Server 2017 и Azure SQLhttps://www.postgresql.org/docs/current/static/functions-aggregate.html
https://docs.microsoft.com/en-us/sql/t-sql/ функции / строка-agg-transact-sql
GROUP_CONCAT()
в MySQLhttp://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
(Спасибо @Brianjorden и @milanio за обновление Azure)
Пример кода:
SQL Fiddle: http://sqlfiddle.com/#!18/89251/1
источник
STRING_AGG
был перенесен на 2017 год. Он недоступен в 2016 году.Хотя ответ @serge правильный, но я сравнил потребление времени его пути с xmlpath, и я обнаружил, что xmlpath намного быстрее. Я напишу код сравнения, и вы сможете проверить сами. Это способ @serge:
И это путь xmlpath:
источник
Обновление: MS SQL Server 2017+, База данных SQL Azure
Вы можете использовать:
STRING_AGG
.Использование для запроса OP довольно просто:
Читать далее
Что ж, мой старый не ответ был по праву удален (слева нетронутым ниже), но если кто-то случайно попадет сюда в будущем, есть хорошие новости. Они также внедрили STRING_AGG () в базу данных SQL Azure. Это должно обеспечить точную функциональность, первоначально запрошенную в этом посте, с собственной и встроенной поддержкой. @hrobky упоминал об этом ранее как о функции SQL Server 2016 в то время.
--- Старое сообщение: здесь недостаточно репутации, чтобы напрямую ответить на @hrobky, но STRING_AGG выглядит отлично, однако в настоящее время он доступен только в SQL Server 2016 vNext. Надеюсь, вскоре он появится и в базе данных Azure SQL.
источник
STRING_AGG()
заявлено, что она станет доступной в SQL Server 2017 на любом уровне совместимости. docs.microsoft.com/en-us/sql/t-sql/functions/…Вы можете использовать + = для объединения строк, например:
если вы выберете @test, все имена будут объединены
источник
select @test += name + ', ' from names
ORDER BY
в вашем запросе. Вам следует использовать одну из перечисленных альтернатив.Я нашел ответ Сержа очень многообещающим, но я также столкнулся с проблемами производительности, когда он был написан. Однако, когда я реструктурировал его, чтобы использовать временные таблицы и не включать двойные таблицы CTE, производительность упала с 1 минуты 40 секунд до долей секунды для 1000 комбинированных записей. Вот он для тех, кому нужно сделать это без FOR XML в старых версиях SQL Server:
источник