Как распарсить xml файл в sql
Функции и подобные им выражения, описанные в этом разделе, работают со значениями типа xml . Информацию о типе xml вы можете найти в Разделе 8.13. Выражения xmlparse и xmlserialize , преобразующие значения xml в текст и обратно, здесь повторно не рассматриваются. Для использования большинства этих функций дистрибутив должен быть собран с ключом configure —with-libxml .
9.14.1. Создание XML-контента
Для получения XML-контента из данных SQL существует целый набор функций и функциональных выражений, особенно полезных для выдачи клиентским приложениям результатов запроса в виде XML-документов.
9.14.1.1. xmlcomment
xmlcomment(текст)
Функция xmlcomment создаёт XML-значение, содержащее XML-комментарий с заданным текстом. Этот текст не должен содержать « — » или заканчиваться знаком « — » , чтобы результирующая конструкция была допустимой в XML. Если аргумент этой функции NULL, результатом её тоже будет NULL.
SELECT xmlcomment(‘hello’); xmlcomment —————
9.14.1.2. xmlconcat
xmlconcat(xml[, . ])
Функция xmlconcat объединяет несколько XML-значений и выдаёт в результате один фрагмент XML-контента. Значения NULL отбрасываются, так что результат будет равен NULL, только если все аргументы равны NULL.
SELECT xmlconcat('', 'foo '); xmlconcat ---------------------- foo
XML-объявления, если они присутствуют, обрабатываются следующим образом. Если во всех аргументах содержатся объявления одной версии XML, эта версия будет выдана в результате; в противном случае версии не будет. Если во всех аргументах определён атрибут standalone со значением « yes » , это же значение будет выдано в результате. Если во всех аргументах есть объявление standalone, но минимум в одном со значением « no » , в результате будет это значение. В противном случае в результате не будет объявления standalone. Если же окажется, что в результате должно присутствовать объявление standalone, а версия не определена, тогда в результате будет выведена версия 1.0, так как XML-объявление не будет допустимым без указания версии. Указания кодировки игнорируются и будут удалены в любых случаях.
SELECT xmlconcat('', ''); xmlconcat -----------------------------------
9.14.1.3. xmlelement
xmlelement(nameимя[, xmlattributes(значение[ASатрибут] [, . ])] [, содержимое, .])
Выражение xmlelement создаёт XML-элемент с заданным именем, атрибутами и содержимым.
SELECT xmlelement(name foo); xmlelement ------------SELECT xmlelement(name foo, xmlattributes('xyz' as bar)); xmlelement ------------------ SELECT xmlelement(name foo, xmlattributes(current_date as bar), 'cont', 'ent'); xmlelement ------------------------------------- content
Если имена элементов и атрибутов содержат символы, недопустимые в XML, эти символы заменяются последовательностями _x HHHH _ , где HHHH — шестнадцатеричный код символа в Unicode. Например:
SELECT xmlelement(name "foo$bar", xmlattributes('xyz' as "a&b")); xmlelement ----------------------------------
Если в качестве значения атрибута используется столбец таблицы, имя атрибута можно не указывать явно, этим именем станет имя столбца. Во всех остальных случаях имя атрибута должно быть определено явно. Таким образом, это выражение допустимо:
CREATE TABLE test (a xml, b xml); SELECT xmlelement(name test, xmlattributes(a, b)) FROM test;
А следующие варианты — нет:
SELECT xmlelement(name test, xmlattributes('constant'), a, b) FROM test; SELECT xmlelement(name test, xmlattributes(func(a, b))) FROM test;
Содержимое элемента, если оно задано, будет форматировано согласно его типу данных. Когда оно само имеет тип xml , из него можно конструировать сложные XML-документы. Например:
SELECT xmlelement(name foo, xmlattributes('xyz' as bar), xmlelement(name abc), xmlcomment('test'), xmlelement(name xyz)); xmlelement ----------------------------------------------
Содержимое других типов будет оформлено в виде блока символьных данных XML. Это, в частности, означает, что символы и & будут преобразованы в сущности XML. Двоичные данные (данные типа bytea ) представляются в кодировке base64 или в шестнадцатеричном виде, в зависимости от значения параметра xmlbinary. Следует ожидать, что конкретные представления отдельных типов данных могут быть изменены для приведения типов SQL и PostgreSQL в соответствие со стандартом XML Schema, когда появится его более полное описание.
9.14.1.4. xmlforest
xmlforest(содержимое[ASимя] [, . ])
Выражение xmlforest создаёт последовательность XML-элементов с заданными именами и содержимым.
SELECT xmlforest('abc' AS foo, 123 AS bar); xmlforest ------------------------------ abc 123 SELECT xmlforest(table_name, column_name) FROM information_schema.columns WHERE table_schema = 'pg_catalog'; xmlforest ------------------------------------------------------------------------------------------- pg_authid rolname pg_authid rolsuper .
Как показано во втором примере, имя элемента можно опустить, если источником содержимого служит столбец (в этом случае именем элемента по умолчанию будет имя столбца). В противном случае это имя необходимо указывать.
Имена элементов с символами, недопустимыми для XML, преобразуются так же, как и для xmlelement . Данные содержимого тоже приводятся к виду, допустимому для XML (кроме данных, которые уже имеют тип xml ).
Заметьте, что такие XML-последовательности не являются допустимыми XML-документами, если они содержат больше одного элемента на верхнем уровне, поэтому может иметь смысл вложить выражения xmlforest в xmlelement .
9.14.1.5. xmlpi
xmlpi(nameцель[,содержимое])
Выражение xmlpi создаёт инструкцию обработки XML. Содержимое, если оно задано, не должно содержать последовательность символов ?> .
SELECT xmlpi(name php, ‘echo «hello world»;’); xmlpi ——————————
9.14.1.6. xmlroot
xmlroot(xml, versionтекст| нет значения [, standalone yes|no|нет значения])
Выражение xmlroot изменяет свойства корневого узла XML-значения. Если в нём указывается версия, она заменяет значение в объявлении версии корневого узла; также в корневой узел переносится значение свойства standalone.
SELECT xmlroot(xmlparse(document 'abc '), version '1.0', standalone yes); xmlroot ----------------------------------------abc
9.14.1.7. xmlagg
xmlagg(xml)
Функция xmlagg , в отличие от других описанных здесь функций, является агрегатной. Она соединяет значения, поступающие на вход агрегатной функции, подобно функции xmlconcat , но делает это, обрабатывая множество строк, а не несколько выражений в одной строке. Дополнительно агрегатные функции описаны в Разделе 9.20.
CREATE TABLE test (y int, x xml); INSERT INTO test VALUES (1, 'abc '); INSERT INTO test VALUES (2, ''); SELECT xmlagg(x) FROM test; xmlagg ----------------------abc
Чтобы задать порядок сложения элементов, в агрегатный вызов можно добавить предложение ORDER BY , описанное в Подразделе 4.2.7. Например:
SELECT xmlagg(x ORDER BY y DESC) FROM test; xmlagg ----------------------abc
Следующий нестандартный подход рекомендовался в предыдущих версиях и может быть по-прежнему полезен в некоторых случаях:
SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab; xmlagg ----------------------abc
9.14.2. Условия с XML
Описанные в этом разделе выражения проверяют свойства значений xml .
9.14.2.1. IS DOCUMENT
xml IS DOCUMENT
Выражение IS DOCUMENT возвращает true, если аргумент представляет собой правильный XML-документ, false в противном случае (т. е. если это фрагмент содержимого) и NULL, если его аргумент также NULL. Чем документы отличаются от фрагментов содержимого, вы можете узнать в Разделе 8.13.
9.14.2.2. IS NOT DOCUMENT
xml IS NOT DOCUMENT
Выражение IS NOT DOCUMENT возвращает false, если аргумент представляет собой правильный XML-документ, true в противном случае (т. е. если это фрагмент содержимого) и NULL, если его аргумент — NULL.
9.14.2.3. XMLEXISTS
XMLEXISTS(текстPASSING [BY REF]xml[BY REF])
Функция xmlexists возвращает true, если выражение XPath в первом аргументе возвращает какие либо узлы, и false — в противном случае. (Если один из аргументов равен NULL, результатом также будет NULL.)
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF 'Toronto Ottawa '); xmlexists ------------ t (1 row)
Указания BY REF не несут смысловой нагрузки в PostgreSQL, но могут присутствовать для соответствия стандарту SQL и совместимости с другими реализациями. По стандарту SQL первое указание BY REF является обязательным, а второе — нет. Также заметьте, что, согласно стандарту SQL, конструкция xmlexists должна принимать в первом аргументе выражение XQuery, но PostgreSQL в настоящее время поддерживает только XPath, подмножество XQuery.
9.14.2.4. xml_is_well_formed
xml_is_well_formed(текст)xml_is_well_formed_document(текст)xml_is_well_formed_content(текст)
Эти функции проверяют, является ли текст правильно оформленным XML, и возвращают соответствующее логическое значение. Функция xml_is_well_formed_document проверяет аргумент как правильно оформленный документ, а xml_is_well_formed_content — правильно оформленное содержание. Функция xml_is_well_formed может делать первое или второе, в зависимости от значения параметра конфигурации xmloption ( DOCUMENT или CONTENT , соответственно). Это значит, что xml_is_well_formed помогает понять, будет ли успешным простое приведение к типу xml , тогда как две другие функции проверяют, будут ли успешны соответствующие варианты XMLPARSE .
SET xmloption TO DOCUMENT; SELECT xml_is_well_formed('<>'); xml_is_well_formed -------------------- f (1 row) SELECT xml_is_well_formed(''); xml_is_well_formed -------------------- t (1 row) SET xmloption TO CONTENT; SELECT xml_is_well_formed('abc'); xml_is_well_formed -------------------- t (1 row) SELECT xml_is_well_formed_document('bar '); xml_is_well_formed_document ----------------------------- t (1 row) SELECT xml_is_well_formed_document('bar'); xml_is_well_formed_document ----------------------------- f (1 row)
Последний пример показывает, что при проверке также учитываются сопоставления пространств имён.
9.14.3. Обработка XML
Для обработки значений типа xml с помощью выражений XPath 1.0 в PostgreSQL представлены функции xpath и xpath_exists .
xpath(xpath,xml[,nsarray])
Функция xpath вычисляет выражение XPath (аргумент xpath типа text ) для заданного xml . Она возвращает массив XML-значений с набором узлов, полученных при вычислении выражения XPath. Если выражение XPath выдаёт не набор узлов, а скалярное значение, возвращается массив из одного элемента.
Вторым аргументом должен быть правильно оформленный XML-документ. В частности, в нём должен быть единственный корневой элемент.
В необязательном третьем аргументе функции передаются сопоставления пространств имён. Эти сопоставления должны определяться в двумерном массиве типа text , во второй размерности которого 2 элемента (т. е. это должен быть массив массивов, состоящих из 2 элементов). В первом элементе каждого массива определяется псевдоним (префикс) пространства имён, а во втором — его URI. Псевдонимы, определённые в этом массиве, не обязательно должны совпадать с префиксами пространств имён в самом XML-документе (другими словами, для XML-документа и функции xpath псевдонимы имеют локальный характер).
SELECT xpath('/my:a/text()', 'test ', ARRAY[ARRAY['my', 'http://example.com']]); xpath -------- (1 row)
Для пространства имён по умолчанию (анонимного) это выражение можно записать так:
SELECT xpath('//mydefns:b/text()', 'test', ARRAY[ARRAY['mydefns', 'http://example.com']]); xpath -------- (1 row)
xpath_exists(xpath,xml[,nsarray])
Функция xpath_exists представляет собой специализированную форму функции xpath . Она возвращает не весь набор XML-узлов, удовлетворяющих выражению XPath, а только одно логическое значение, показывающее, есть ли такие узлы. Эта функция равнозначна стандартному условию XMLEXISTS , за исключением того, что она также поддерживает сопоставления пространств имён.
SELECT xpath_exists('/my:a/text()', 'test ', ARRAY[ARRAY['my', 'http://example.com']]); xpath_exists -------------- t (1 row)
9.14.4. Отображение таблиц в XML
Следующие функции отображают содержимое реляционных таблиц в значения XML. Их можно рассматривать как средства экспорта в XML:
table_to_xml(tbl regclass, nulls boolean, tableforest boolean, targetns text) query_to_xml(query text, nulls boolean, tableforest boolean, targetns text) cursor_to_xml(cursor refcursor, count int, nulls boolean, tableforest boolean, targetns text)
Результат всех этих функций имеет тип xml .
table_to_xml отображает в xml содержимое таблицы, имя которой задаётся в параметре tbl . Тип regclass принимает идентификаторы строк в обычной записи, которые могут содержать указание схемы и кавычки. Функция query_to_xml выполняет запрос, текст которого передаётся в параметре query , и отображает в xml результирующий набор. Последняя функция, cursor_to_xml выбирает указанное число строк из курсора, переданного в параметре cursor . Этот вариант рекомендуется использовать с большими таблицами, так как все эти функции создают результирующий xml в памяти.
Если параметр tableforest имеет значение false, результирующий XML-документ выглядит так:
<имя_таблицы><имя_столбца1>данныеимя_столбца1> <имя_столбца2>данныеимя_столбца2>
.
.имя_таблицы>
А если tableforest равен true, в результате будет выведен следующий фрагмент XML:
<имя_таблицы> <имя_столбца1>данныеимя_столбца1> <имя_столбца2>данныеимя_столбца2> имя_таблицы> <имя_таблицы>.имя_таблицы> .
Если имя таблицы неизвестно, например, при отображении результатов запроса или курсора, вместо него в первом случае вставляется table , а во втором — row .
Выбор между этими форматами остаётся за пользователем. Первый вариант позволяет создать готовый XML-документ, что может быть полезно для многих приложений, а второй удобно применять с функцией cursor_to_xml , если её результаты будут собираться в документ позже. Полученный результат можно изменить по вкусу с помощью рассмотренных выше функций создания XML-содержимого, в частности xmlelement .
Значения данных эти функции отображают так же, как и ранее описанная функция xmlelement .
Параметр nulls определяет, нужно ли включать в результат значения NULL. Если он установлен, значения NULL в столбцах представляются так:
Здесь xsi — префикс пространства имён XML Schema Instance. При этом в результирующий XML будет добавлено соответствующее объявление пространства имён. Если же данный параметр равен false, столбцы со значениями NULL просто не будут выводиться.
Параметр targetns определяет целевое пространство имён для результирующего XML. Если пространство имён не нужно, значением этого параметра должна быть пустая строка.
Следующие функции выдают документы XML Schema, которые содержат схемы отображений, выполняемых соответствующими ранее рассмотренными функциями:
table_to_xmlschema(tbl regclass, nulls boolean, tableforest boolean, targetns text) query_to_xmlschema(query text, nulls boolean, tableforest boolean, targetns text) cursor_to_xmlschema(cursor refcursor, nulls boolean, tableforest boolean, targetns text)
Чтобы результаты отображения данных в XML соответствовали XML-схемам, важно, чтобы паре функций передавались одинаковые параметры.
Следующие функции выдают отображение данных в XML и соответствующую XML-схему в одном документе (или фрагменте), объединяя их вместе. Это может быть полезно там, где желательно получить самодостаточные результаты с описанием:
table_to_xml_and_xmlschema(tbl regclass, nulls boolean, tableforest boolean, targetns text) query_to_xml_and_xmlschema(query text, nulls boolean, tableforest boolean, targetns text)
В дополнение к ним есть следующие функции, способные выдать аналогичные представления для целых схем в базе данных или даже всей текущей базы данных:
schema_to_xml(schema name, nulls boolean, tableforest boolean, targetns text) schema_to_xmlschema(schema name, nulls boolean, tableforest boolean, targetns text) schema_to_xml_and_xmlschema(schema name, nulls boolean, tableforest boolean, targetns text) database_to_xml(nulls boolean, tableforest boolean, targetns text) database_to_xmlschema(nulls boolean, tableforest boolean, targetns text) database_to_xml_and_xmlschema(nulls boolean, tableforest boolean, targetns text)
Заметьте, что объём таких данных может быть очень большим, а XML будет создаваться в памяти. Поэтому, вместо того, чтобы пытаться отобразить в XML сразу всё содержимое больших схем или баз данных, лучше делать это по таблицам, возможно даже используя курсор.
Результат отображения содержимого схемы будет выглядеть так:
<имя_схемы>отображение-таблицы1 отображение-таблицы2 .имя_схемы>
Формат отображения таблицы определяется параметром tableforest , описанным выше.
Результат отображения содержимого базы данных будет таким:
Здесь отображение схемы имеет вид, показанный выше.
В качестве примера, иллюстрирующего использование результата этих функций, на Примере 9.1 показано XSLT-преобразование, которое переводит результат функции table_to_xml_and_xmlschema в HTML-документ, содержащий таблицу с данными. Подобным образом результаты этих функций можно преобразовать и в другие форматы на базе XML.
Пример 9.1. XSLT-преобразование, переводящее результат SQL/XML в формат HTML
| Пред. | Наверх | След. |
| 9.13. Функции и операторы текстового поиска | Начало | 9.15. Функции и операторы JSON |
Распарсить сложный XML
Ошибка The error description is ‘An invalid character was found in text content.’.
Если бы не было тегов и , то все бы хорошо разобралось.
А так не знаю, что и делать. Подскажите, пожалуйста!
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
сложный запрос sql xml
1. Сoздaть пepeмeнную типa XML, кoтopaя coдepжит в иepapхичecкoм видe дaнныe o гpуппaх .
Распарсить xml
Здравствуйте! Ребята, подскажите, каким образом можно корректно распарить xml документ при помощи.
Распарсить XML
Доброго времени суток. Есть xml файл следующего в которых имеются записи следующего содержания: .
3363 / 2059 / 736
Регистрация: 02.06.2013
Сообщений: 5,044
Сообщение от Lenoshka 
А так не знаю, что и делать. Подскажите, пожалуйста!
Нельзя обработать невалидный xml. Поэтому либо требуйте у авторов валидный xml, либо приводите сами к валидному виду.
Регистрация: 22.02.2013
Сообщений: 117
Записей в блоге: 2
Проверила XML на корректность — все нормально. Схемы для проверки валидности нет. А какой вид нормальный для данного документа?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
> > >112 > >0 > >99 > >43 > >gfdf > >AM|MC > > > > >1388 > >0 > >3 > > > >Here is some text > > > > >20141215 17:25:31 > >ghgj > >.. > > >
Он же вроде бы отвечает всем требованиям?
Спасибо!
19 / 19 / 12
Регистрация: 09.12.2014
Сообщений: 250
Lenoshka, вот что выдал на ваш последний хмл файл мой редактор:
Тег конца «ac» не соответствует тегу начала «acc». Ошибка при обработке ресурса »file:///D:/kml.xml». Строка 14,По.
у вас и в 1 посте ошибка в теге: и в последнем:
вам нужно следить за синтаксисом и всё у вас получится.
Регистрация: 22.02.2013
Сообщений: 117
Записей в блоге: 2
texnix, Это не проблема в синтаксисе, это опечатка (реальные названия не хотелось бы показывать, т.к. это рабочий документ). В оригинале открывающие/закрывающие теги совпадают
19 / 19 / 12
Регистрация: 09.12.2014
Сообщений: 250
1 2 3 4 5 6 7 8 9 10 11 12 13 14
DECLARE @idoc int, @doc varchar(1000); SET @doc =' '; --Create an internal representation of the XML document. EXEC sp_xml_preparedocument @idoc OUTPUT, @doc; -- Execute a SELECT statement that uses the OPENXML rowset provider. SELECT * FROM OPENXML (@idoc, '/root/header',1) WITH (IMT varchar(10) ,[AS] int);
вот такую штуку у меня скуэль сьел и не подавился. Может быть вам стоит распарсить функциями работы со строками ваш xml к такому виду?
3363 / 2059 / 736
Регистрация: 02.06.2013
Сообщений: 5,044
Сообщение от Lenoshka 
Проверила XML на корректность — все нормально.
Вы можете считать, что сервер вас дурит, сообщая о несуществующей ошибке. Только это бесперспективный путь.
Регистрация: 22.02.2013
Сообщений: 117
Записей в блоге: 2
Я не считаю, что сервер меня обманывает, я пытаюсь понять, в чем у нас взгляды на корректность расходятся.
Эх. Придется элементы в атрибуты превращать.
Сообщение вида
1 2 3 4 5 6 7 8 9
> IMT="112" AS="0" IS="1388" ISS="0" IC="107032" BT="AM|MC"/> > A="0" pm="0" acc="3"/> Msg="some text"/> > MDTe="20141216 15:43:16" IdK="54671" SM=". "/> >
Как сделать быстрый парсинг XML и запись в базу?
Как быстрее произвести сам парсинг и затем сделать insert в бд?
На данный момент использую такой алгоритм, но при больших файлах(и когда файлов много) читает xml и делает insert долго.
Есть ли другой алгоритм быстрее распарсить xml и сделать insert не по каждой записи а группой?
Например сразу записать все что есть в ZAP в client_table , потом DATA вusl_table
import xml.etree.cElementTree as ET tree = ET.parse(filexml) element_xml_root = tree.getroot() dbcur = db.cursor() for elem in element_xml_root.findall('ZAP'): idclient = elem.find('ID_CLIENT').text fam = elem.find('FAM').text im = elem.find('IM') .text ot = elem.find('OT') .text query_pac = dbcur.prepare('INSERT INTO client_table (idclient, fam, im, ot)' ' VALUES (:idclient, : fam, : im, : ot)') dbcur.execute(query_pac, (idpac, fam, im, ot)) for data in elem.findall('DATA'): code_usl = data.find('CODE') .text date_usl = data.find('DATE') .text price_usl = data.find('PRICE') .text query_usl = dbcur.prepare('INSERT INTO usl_table (idpac, code_usl, date_usl, price_usl)' ' VALUES (:idpac, : code_usl, : date_usl, : price_usl)') dbcur.execute(query_usl, (idpac, code_usl, date_usl, price_usl)) db.commit() dbcur.close()
- Вопрос задан более трёх лет назад
- 4246 просмотров
1 комментарий
Простой 1 комментарий
Сергей Горностаев @sergey-gornostaev Куратор тега Python
Используйте SAX-парсер для разбора больших xml-файлов и заворачивайте в транзакцию вставку блоков данных в базу.
Решения вопроса 1

Сергей П @trapwalker Куратор тега Python
Программист, энтузиаст
Прологируйте подробно вашу функцию и вы поймёте что больше тормозит.
Основных проблемы может быть три:
1) Долгий парсинг XML. Его время зависит от размера файла, а вставлять в базу вы начнете только по окончании парсинга. При этом весь файл в виде объектного дерева у вас будет в памяти. что может быть очень неэффективно.
2) Долгий поиск нужных элементов в дереве. Это сомнительно, что он тут будет существенно тормозить на фоне прочих процессов.
3) Долгая вставка из-за отдельных транзакций на каждую.
1,2) Первая проблема может быть решена потоковым чтением XML через SAX-парсер. На закрытие определенных тегов вешаются события, а объект-парсер накапливает данные в своём состоянии. Это позволит получать данные по мере чтения и парсинга файла, а не после. Вторая проблема, кстати, то же решается sax-парсером. Просто не будет дополнительных накладных расходов на обход построенного парсером дерева.
Как правильно распарсить xml sql?
Подскажите как правильно распарсить xml не зная названий его полей, но зная что он без уровня вложенности? Например есть такой xml:
37 84018 56 20 2018-02-01
Ну и нужно чтобы на выходе получилось вот так:
+------+--------+---------+---------+------------+ | id | order | city | country | date | +------+--------+---------+---------+------------+ | 37 | 84018 | 56 | 20 | 2018-02-01 | +------+--------+---------+---------+------------+
Отслеживать
5,923 17 17 серебряных знаков 32 32 бронзовых знака
задан 10 апр 2018 в 14:22
107 1 1 серебряный знак 9 9 бронзовых знаков
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
С помощью динамического PIVOT, который позволяет поменять местами столбцы со строками в таблице, можно добиться требуемого результата
Вот полный рабочий пример:
DECLARE @XML as xml SELECT @XML = ' 37 84018 56 20 2018-02-01 ' IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL DROP TABLE #tempTable create table #tempTable ( NodeName nvarchar(max), NodeValue nvarchar(max) ) INSERT INTO #tempTable (NodeName, NodeValue) (SELECT a.b.value('local-name(.)', 'VARCHAR(MAX)') as NodeName, a.b.value('.', 'VARCHAR(MAX)') As NodeValue FROM @xml.nodes('//*[not(*)]') AS a(b) ) Declare @Cols AS NVARCHAR(MAX),@SQL AS NVARCHAR(MAX); Set @Cols = Stuff((Select Distinct ',' + QuoteName(NodeName) From #tempTable For XML Path(''), Type ).value('.', 'varchar(max)'),1,1,'') Set @SQL = 'Select * From #tempTable Pivot ( max(NodeValue) For [NodeName] in (' + @Cols + ') ) p ' Exec (@SQL)
Как это работает:
- Создаем временную таблицу, куда сохраняем имя xml элемента и его значение узлов, полученных c использованием функции nodes для типа данных xml. Строка запроса, равная //*[not(*)] означает — выбрать все элементы, за исключением элементов, у которых есть дочерние элементы. Тем самым, мы исключаем элемент root из выборки, он нам не нужен. В этой строке у нас два столбца, в одном из которых содержится название xml элемента, в другом — его значение
- Объединяем все значения столбца NodeName в одну строку, разделенных символом «,» и сохраняем в переменной @Cols . Строка с названиями столбцов необходима для выполнения операции PIVOT. Данные строки столбца NodeName должны стать строками.
- Применяем наконец сам PIVOT для конвертации строк и столбцов к нашей созданной временной таблице — для каждого столбца в переменной @Cols выбираем соответствующее максимальное значение поля NodeValue .
Применяем агрегатную функцию для всех строк, где значение поля NodeName из строки изначальной таблицы равно имени столбца из набора @Cols . В нашем примере повторяющихся строк нет, все значение в столбце NodeName уникальны, но агрегатная функция необходима, я использую функцию max.
В результате получаем перевернутую таблицу в том виде, в котором нам необходимо.
