使用 T-SQL 将表转换为 XML

Posted

技术标签:

【中文标题】使用 T-SQL 将表转换为 XML【英文标题】:Convert Tables into XML using T-SQL 【发布时间】:2014-07-12 02:08:01 【问题描述】:

如果发现了几个关于如何将表(或查询)转换为 XML 的问题,但没有一个显示如何从一个主表开始并连接多个 one:many 附属表,并从中生成表示层次结构的 XML的数据。所以我想既然我已经弄清楚了,我会分享这个解决方案。如果其他人有其他方法,请发布另一个答案。

鉴于这些人为的数据:

create table #recipe (id int, name varchar(10))
create table #ingredient (recipe_id int, name varchar(30), quantity varchar(20), sort int)
create table #instruction (recipe_id int, task varchar(32), sort int)

insert into #recipe values (1, 'pizza'), (2, 'omelet')
insert into #ingredient values (1, 'pizza dough', '1 package', 1),
                               (1, 'tomato sauce', '1 can', 2),
                               (1, 'favorite toppings', 'you choose', 3),
                               (2, 'eggs', 'three', 1),
                               (2, 'a bunch of other ingredients', 'you choose', 2)
insert into #instruction values (1, 'pre-bake pizza dough', 1),
                                (1, 'add tomato sauce', 2),
                                (1, 'add toppings', 3),
                                (1, 'bake a little longer', 4),
                                (2, 'break eggs into mixing bowl', 1),
                                (2, 'beat yolks and whites together', 2),
                                (2, 'pour into large sauce pan', 3),
                                (2, 'add other ingredients', 4),
                                (2, 'fold in half', 5),
                                (2, 'cook until done', 6)

.

表格形式如下:

#recipe

id          name
----------- ----------
1           pizza
2           omelet

.

#ingredient

recipe_id   name                           quantity             sort
----------- ------------------------------ -------------------- -----------
1           pizza dough                    1 package            1
1           tomato sauce                   1 can                2
1           favorite toppings              you choose           3
2           eggs                           three                1
2           a bunch of other ingredients   you choose           2

.

#instruction

recipe_id   task                             sort
----------- -------------------------------- -----------
1           pre-bake pizza dough             1
1           add tomato sauce                 2
1           add toppings                     3
1           bake a little longer             4
2           break eggs into mixing bowl      1
2           beat yolks and whites together   2
2           pour into large sauce pan        3
2           add other ingredients            4
2           fold in half                     5
2           cook until done                  6

.

我想创建一个 XML 文档,其中每个食谱都有一个记录,并且在每个食谱元素中,我想要一组成分和另一组指令,如下所示:

<recipes>
  <recipe id="2" name="omelet">
    <ingredients>
      <ingredient name="eggs" quantity="three" />
      <ingredient name="a bunch of other ingredients" quantity="you choose" />
    </ingredients>
    <instructions>
      <instruction task="break eggs into mixing bowl" />
      <instruction task="beat yolks and whites together" />
      <instruction task="pour into large sauce pan" />
      <instruction task="add other ingredients" />
      <instruction task="fold in half" />
      <instruction task="cook until done" />
    </instructions>
  </recipe>
  <recipe id="1" name="pizza">
    <ingredients>
      <ingredient name="pizza dough" quantity="1 package" />
      <ingredient name="tomato sauce" quantity="1 can" />
      <ingredient name="favorite toppings" quantity="you choose" />
    </ingredients>
    <instructions>
      <instruction task="pre-bake pizza dough" />
      <instruction task="add tomato sauce" />
      <instruction task="add toppings" />
      <instruction task="bake a little longer" />
    </instructions>
  </recipe>
</recipes>

【问题讨论】:

【参考方案1】:

此 SQL 逐字创建所需的 XML:

select recipe.*,
       (
         select ingredient.name, ingredient.quantity
         from   #ingredient ingredient
         where recipe.id = ingredient.recipe_id
         order by ingredient.sort
         for xml auto, root('ingredients'), type
       ),
       (
         select instruction.task
         from   #instruction instruction
         where  recipe.id = instruction.recipe_id
         order by instruction.sort
         for xml auto, root('instructions'), type
       )
from   #recipe as recipe
order by recipe.name
for xml auto, root('recipes'), type

我为临时表名称起了别名,因为在临时表上使用 for xml auto 会创建名称不佳的 XML 元素。看起来是这样的:

<recipes>
  <recipe id="2" name="omelet">
    <ingredients>
      <ingredient name="eggs" quantity="three" />
      <ingredient name="a bunch of other ingredients" quantity="you choose" />
    </ingredients>
    <instructions>
      <instruction task="break eggs into mixing bowl" />
      <instruction task="beat yolks and whites together" />
      <instruction task="pour into large sauce pan" />
      <instruction task="add other ingredients" />
      <instruction task="fold in half" />
      <instruction task="cook until done" />
    </instructions>
  </recipe>
  <recipe id="1" name="pizza">
    <ingredients>
      <ingredient name="pizza dough" quantity="1 package" />
      <ingredient name="tomato sauce" quantity="1 can" />
      <ingredient name="favorite toppings" quantity="you choose" />
    </ingredients>
    <instructions>
      <instruction task="pre-bake pizza dough" />
      <instruction task="add tomato sauce" />
      <instruction task="add toppings" />
      <instruction task="bake a little longer" />
    </instructions>
  </recipe>
</recipes>

.

此 SQL 创建 XML 的另一个版本,其中所有数据都作为值而不是属性,但具有相同的基本层次结构:

select recipe.*,
       (
         select ingredient.name, ingredient.quantity
         from   #ingredient ingredient
         where recipe.id = ingredient.recipe_id
         order by ingredient.sort
         for xml path('ingredient'), root('ingredients'), type
       ),
       (
         select instruction.task
         from   #instruction instruction
         where  recipe.id = instruction.recipe_id
         order by instruction.sort
         for xml path('instruction'), root('instructions'), type
       )
from   #recipe as recipe
order by recipe.name
for xml path('recipe'), root('recipes'), type

.

看起来是这样的:

<recipes>
  <recipe>
    <id>2</id>
    <name>omelet</name>
    <ingredients>
      <ingredient>
        <name>eggs</name>
        <quantity>three</quantity>
      </ingredient>
      <ingredient>
        <name>a bunch of other ingredients</name>
        <quantity>you choose</quantity>
      </ingredient>
    </ingredients>
    <instructions>
      <instruction>
        <task>break eggs into mixing bowl</task>
      </instruction>
      <instruction>
        <task>beat yolks and whites together</task>
      </instruction>
      <instruction>
        <task>pour into large sauce pan</task>
      </instruction>
      <instruction>
        <task>add other ingredients</task>
      </instruction>
      <instruction>
        <task>fold in half</task>
      </instruction>
      <instruction>
        <task>cook until done</task>
      </instruction>
    </instructions>
  </recipe>
  <recipe>
    <id>1</id>
    <name>pizza</name>
    <ingredients>
      <ingredient>
        <name>pizza dough</name>
        <quantity>1 package</quantity>
      </ingredient>
      <ingredient>
        <name>tomato sauce</name>
        <quantity>1 can</quantity>
      </ingredient>
      <ingredient>
        <name>favorite toppings</name>
        <quantity>you choose</quantity>
      </ingredient>
    </ingredients>
    <instructions>
      <instruction>
        <task>pre-bake pizza dough</task>
      </instruction>
      <instruction>
        <task>add tomato sauce</task>
      </instruction>
      <instruction>
        <task>add toppings</task>
      </instruction>
      <instruction>
        <task>bake a little longer</task>
      </instruction>
    </instructions>
  </recipe>
</recipes>

最初我尝试将配料和说明放在主查询的from 子句中,并在配方表中添加inner join。但是说明都嵌套在成分中,成分嵌套在配方中。当我将它们移到查询的 select 部分时,它理顺了 XML。

【讨论】:

我怀疑这个例子对其他人有任何用处。

以上是关于使用 T-SQL 将表转换为 XML的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL谜题:将表的每一行作为内联函数的输入传递,并使用UNION ALL开发新的堆栈数据集

在单个查询中将VARCHAR(max)列转换为大写,然后转换为XML

存储过程:将表名转换为表变量

如何使用 JDBC 接收器连接器将表名转换为大写

Delphi:如何将表结构转换为对象

在 T-SQL 中将多行转换为具有多列的一行