На это отвечали много раз, но у меня такое ощущение, что какое-то объяснение может помочь вам ...
... я что-то упустил?Похоже, что это связано с XML
Необходимая функциональность STRING_AGG () была введена в SQL-Server 2017. Другое направление STRING_SPLIT () пришлос v2016.
Но многие люди все еще используют более старые версии (и будут делать это годами), поэтому нам нужны обходные пути.Были подходы с циклами, плохие и медленные ... И вы могли бы использовать рекурсивные CTE.И - вот в чем дело!- мы можем использовать некоторые возможности XML для решения этой проблемы.
Попробуйте это:
DECLARE @xml XML=
N'<root>
<element>text1</element>
<element>text2</element>
<element>text3</element>
</root>';
- Запрос вернет первый <element>
ниже <root>
и вернет text1 .
SELECT @xml.value(N'(/root/element)[1]','nvarchar(max)');
- Но теперь попробуйте это:
SELECT @xml.value(N'(/root)[1]','nvarchar(max)')
Результат будет text1text2text3 .
Причина этого:Если вы вызовете .value()
для элемента без подробной спецификации , что вы хотите прочитать, вы получите весь элемент обратно.Найти подробности здесь .
Теперь представьте XML-код, подобный этому
DECLARE @xml2 XML=
N'<root>
<element>, text1</element>
<element>, text2</element>
<element>, text3</element>
</root>';
С тем же запросом, что и выше, вы получите , text1, text2, text3.Осталось только отрезать запятую и пробел.Это делается - в большинстве случаев - с помощью STUFF () .
Таким образом, задача состоит в том, чтобы создать этот XML.И это то, что вы найдете в связанных примерах.
Общий пример таков: прочитайте все таблицы и перечислите их столбцы в виде CSV-списка:
SELECT TOP 10
TABLE_NAME
,STUFF(
(SELECT ',' + c.COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_SCHEMA=t.TABLE_SCHEMA AND c.TABLE_NAME=t.TABLE_NAME
ORDER BY c.COLUMN_NAME
FOR XML PATH('')
),1,1,'') AS AllTableColumns
FROM INFORMATION_SCHEMA.TABLES t