Преобразовать таблицу SQL в XML со столбцом в качестве родительского узла - PullRequest
6 голосов
/ 22 сентября 2010

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

У меня есть частьконечно, но у меня нет полного решения.Мне нужно, чтобы столбец TABLE_NAME преобразовывался в родительский узел xml, а столбец COLUMN_NAME - в дочерние узлы.Если я выполняю следующее, я получаю вложенность, но также получаю несколько родительских узлов.

select
 TABLE_NAME AS 'tn',
 COLUMN_NAME AS 'tn/cn'
from (
 select 'TABLE_A' AS TABLE_NAME, 'COLUMN_1' AS COLUMN_NAME
 UNION ALL
 select 'TABLE_A' AS TABLE_NAME, 'COLUMN_2' AS COLUMN_NAME
 UNION ALL
 select 'TABLE_B' AS TABLE_NAME, 'COLUMN_1' AS COLUMN_NAME
 UNION ALL
 select 'TABLE_B' AS TABLE_NAME, 'COLUMN_2' AS COLUMN_NAME
) x
for xml path(''), ROOT('datatable')

OUPUT >>>

<datatable>
  <tn>TABLE_A<cn>COLUMN_1</cn></tn>
  <tn>TABLE_A<cn>COLUMN_2</cn></tn>
  <tn>TABLE_B<cn>COLUMN_1</cn></tn>
  <tn>TABLE_B<cn>COLUMN_2</cn></tn>
</datatable>

DESIRED OUTPUT >>>

<datatable>
  <TABLE_A>
   <cn>COLUMN_1</cn>
   <cn>COLUMN_2</cn>
  </TABLE_A>
  <TABLE_B>
    <cn>COLUMN_1</cn>
    <cn>COLUMN_2</cn>
  </TABLE_B>
</datatable>

Это возможно или я сплю?и возможно ли это без XML EXPLICIT или для этого существует EXPLICIT?

Другая возможность, которую я пробовал, - заполнить xml, а затем применить xquery, но пока это не радует..

Спасибо,

Гари

Ответы [ 4 ]

3 голосов
/ 29 сентября 2010

Как уже упоминалось, FOR XML не позволяет вам динамически именовать узлы.Имена узлов должны быть постоянными ко времени компиляции самого запроса.Вы можете обойти это с помощью динамического sql, но затем вы получите код, который становится все труднее и труднее читать.

Альтернативой может быть ручная генерация узлов имен talbe и CAST в XML:

Настройка:

CREATE TABLE a (table_name VARCHAR(20), column_name VARCHAR(20)
INSERT INTO a VALUES ('TABLE_A', 'COLUMN_1')
INSERT INTO a VALUES ('TABLE_A', 'COLUMN_2')
INSERT INTO a VALUES ('TABLE_B', 'COLUMN_1')
INSERT INTO a VALUES ('TABLE_B', 'COLUMN_2')

Выполнить:

SELECT CAST(
      '<' + table_name + '>'
    + (SELECT c.column_name as 'CN'
         FROM a c
        WHERE c.table_name = p.table_name
       FOR XML PATH('')) 
    + '</' + table_name + '>'
    AS XML)
  FROM a p
GROUP BY p.table_name
FOR XML PATH(''), ROOT('datatable')

Производит:

<datatable>
  <TABLE_A>
    <CN>COLUMN_1</CN>
    <CN>COLUMN_2</CN>
  </TABLE_A>
  <TABLE_B>
    <CN>COLUMN_1</CN>
    <CN>COLUMN_2</CN>
  </TABLE_B>
</datatable>
3 голосов
/ 29 сентября 2010

К сожалению - то, что вы пытаетесь сделать, невозможно.Две основные проблемы (если у вас есть свобода действий, возможно, есть решение).

Во-первых, ни один из параметров XML в SQL (даже не используя EXPLICIT) допускает динамическое именование узлов.Вы можете использовать атрибут <tn id="TABLE_A" /> или значение <tn>TABLE_A</tn>, но вы не можете получить <TABLE_A>, если не установите его жестко.

Типы XML допускают вложение / подзапросы.

SELECT V1.tbname
,(SELECT V2.colname FROM testtable V2 
  WHERE V1.tbname = V2.tbname FOR XML PATH(''), ELEMENTS, TYPE)
FROM testtable V1
FOR XML AUTO, ROOT('datatable')

Ваша вторая проблема связана с тем фактом, что ваши данные денормализованы.Нет никакого способа получить уникальный список таблиц (вы не можете использовать DISTINCT выше, потому что SQL не может сравнивать типы XML).Это ограничивает то, что вы можете сделать за один проход (оператор).

Если вы хотите использовать временную таблицу (или переменную таблицы), вы можете выбрать отдельный список имен таблиц, а затем объединить его симена столбцов, как в приведенном примере (сначала выполните следующее и замените внешнее from на @tblist).

DECLARE @tblist TABLE (tbname varchar(20))
INSERT INTO @tblist SELECT DISTINCT tbname FROM testtable  

Возвращает это:

<datatable>
  <V1 tbname="TBA">
    <colname>COL 1</colname>
    <colname>COL 2</colname>
  </V1>
  <V1 tbname="TBB">
    <colname>COL 1</colname>
    <colname>COL 2</colname>
  </V1>
</datatable>

Вы также должны захотеть, чтобы узлы имен вашей таблицы были атрибутами (вы всегда можете запустить GREP или простую замену впоследствии, чтобы сделатьузел будет оценен) он был бы закрыт, если бы не тот формат, который вы ищете.

Извините - это, вероятно, не то, что вы хотите услышать.Но за пару простых шагов это можно сделать.Просто не напрямую из SQL Server в одном выражении.

2 голосов
/ 22 сентября 2010

Возможно, вам нужно назвать столбцы с путем. Как это: 'parent\child'.

Попробуйте это:

select
( 
 select * from (
     select 'COLUMN_1' 'cn'
     UNION ALL
     select 'COLUMN_2' 'cn' 
 ) as t
 for xml path(''), root('TABLE_A'), type
)
,( 
 select * from (
     select 'COLUMN_1' 'cn'
     UNION ALL
     select 'COLUMN_2' 'cn' 
 ) as t
 for xml path(''), root('TABLE_B'), type
)
for xml path(''), ROOT('datatable')
0 голосов
/ 28 сентября 2010

Проверьте эту очень длинную статью о преобразованиях sql в xml.Надеюсь, это поможет вам -

http://www.stylusstudio.com/sqlxml_tutorial.html

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