SQL 服务器 XML

SQL Server FOR XML

我在 SQL 服务器中有一个 table,它看起来与任何其他 table 一样,具有以下列名:

primaryID | column1 | column2 | column3| column4 | column5

我需要获取 table 中的不同字段并按以下格式创建 XML:

<Record>
<Field id="column1" value="ABCDEFG" />
<Field id="column2" value="Some text" />
<Field id="column3" value="Some other text" />
<Field id="column4" value="myValue" />
<Field id="column5" value="88" />
</Record>

在这种情况下,节点是为 table 中的每条记录创建的。该节点针对该特定记录的每一列完成。 我已经尝试了所有可能的 RAW、PATH、ROOT 和 EXPLICIT 组合,但都无济于事。

我的提议甚至可以在 SQL 服务器中实现,还是我需要在其他地方实现?

您必须指定 xml 路径以获取您想要的节点。

这是一个基于您的示例的示例:

CREATE TABLE #temp  (primaryid INT, column1 VARCHAR(50), column2 VARCHAR(50), column3 VARCHAR(50) ) 
INSERT INTO #Temp (primaryid,   column1, column2, column3 ) VALUES (0, 'abc0', 'some text0', 'myvalue0')
INSERT INTO #Temp (primaryid,   column1, column2, column3 ) VALUES (1, 'abc1', 'some text1', 'myvalue1')

SELECT '',
    (
        SELECT 
            'column1' AS '@id',
            column1 AS '@value'
        FROM #temp a
        WHERE a.primaryid = #temp.primaryid
        FOR XML PATH('Field'), TYPE
    ),
    (
        SELECT 
            'column2' AS '@id',
            column2 AS '@value'
        FROM #temp a
        WHERE a.primaryid = #temp.primaryid
        FOR XML PATH('Field'), TYPE
    ),
    (
        SELECT 
            'column3' AS '@id',
            column3 AS '@value'
        FROM #temp a
        WHERE a.primaryid = #temp.primaryid
        FOR XML PATH('Field'), TYPE
    )
from #Temp
FOR XML PATH('Record'), TYPE


DROP TABLE #temp 

上面的例子产生了这样的结果:

<Record>
  <Field id="column1" value="abc0" />
  <Field id="column2" value="some text0" />
  <Field id="column3" value="myvalue0" />
</Record>
<Record>
  <Field id="column1" value="abc1" />
  <Field id="column2" value="some text1" />
  <Field id="column3" value="myvalue1" />
</Record>

虽然@Avitus 的回答给了你你需要的结果,但在软件开发中,它不仅与结果有关,还与代码的可读性和可维护性有关。所以我决定给你更多的选择:

如果您不介意明确指定列名,这里有一个简单的解决方案 select ... for xml:

1.1。 select ... 对于 xml 自动

select 
    (
        select *
        from (values
            ('column1', column1),
            ('column2', column2),
            ('column3', column3)
        ) as Field(id, value)
        for xml auto, type
    )
from <Table> as Record
for xml auto

1.2。 select ... 对于 xml 原始

select
    (
        select *
        from (values
            ('column1', column1),
            ('column2', column2),
            ('column3', column3)
        ) as Field(id, value)
        for xml raw('Field'), type
    )
from <Table>
for xml raw('Record')

1.3。 select ... 对于 xml 路径

select 
    (
        select *
        from (values
            ('column1', column1),
            ('column2', column2),
            ('column3', column3)
        ) as a([@id], [@value])
        for xml path('Field'), type
    )
from <Table>
for xml path('Record')

更通用的解决方案 - 这些解决方案允许您仅指定您不想在结果中看到的列:

2.1。上面的任何解决方案都包含在动态 SQL

declare @stmt nvarchar(max)

select @stmt = isnull(@stmt + ',','') + '(''' + name + ''', ' + name + ')'
from sys.columns
where
    [object_id] = object_id('<Table>') and
    name not in ('primaryid')

select @stmt = '
        select 
            (
                select *
                from (values ' + @stmt + '
                ) as Field(id, value)
                for xml auto, type
            )
        from <Table> as Record
        for xml auto
'

exec sp_executesql
    @stmt = @stmt

2.2 Double select for xml (xml trick)

;with cte_xml as (
    select (select a.* for xml raw, type) as data
    from #temp as a
)
select
    (
        select  
            t.c.value('local-name(.)', 'nvarchar(128)') as [@id],
            t.c.value('.', 'nvarchar(128)') as [@value]
        from data.nodes('row/@*') as t(c)
        where t.c.value('local-name(.)', 'nvarchar(128)') not in ('primaryid')
        for xml path('Field'), type
    )
from cte_xml
for xml path('Record')