STW*_*STW 4 xml sql-server solr sqlxml
我正在尝试获取一个SQL select语句来生成符合Solr标准的XML.
给出如下表:
id | name
---------
1 | one
2 | two
3 | three
Run Code Online (Sandbox Code Playgroud)
我需要一个像(有或没有根节点)的结果:
<add>
<doc>
<field name="id">1</field>
<field name="name">one</field>
</doc>
<doc>
<field name="id">2</field>
<field name="name">two</field>
</doc>
<doc>
<field name="id">3</field>
<field name="name">three</field>
</doc>
</add>
Run Code Online (Sandbox Code Playgroud)
是否可以使用FOR XML查询生成该结构,还是需要XSLT或其他一些机制来匹配该模式?
这是使用构造函数的略微不同的方式.
DECLARE @sample TABLE
(
[id] int NOT NULL,
[name] varchar(50) NOT NULL
);
INSERT INTO @sample ([id], [name])
SELECT 1, 'one' UNION ALL
SELECT 2, 'two' UNION ALL
SELECT 3, 'three';
SELECT
CONVERT(xml, N'').query
(N'
<doc>
{
element field
{
attribute name {"id"},
text{sql:column("id")}
},
element field
{
attribute name {"name"},
text{sql:column("name")}
}
}
</doc>
')
FROM
@sample
FOR XML PATH(N''), ROOT(N'add');
Run Code Online (Sandbox Code Playgroud)
*编辑:只是想到另一种方法(但仍需要提前知道列)* 再次,我不确定这两种方法的性能影响.
SELECT
(
SELECT
'id' AS [@name],
[id] AS [data()]
FOR XML PATH('field'), TYPE
) AS [*],
(
SELECT
'name' AS [@name],
[name] AS [data()]
FOR XML PATH('field'), TYPE
) AS [*]
FROM
@sample
FOR XML PATH(N'doc'), ROOT(N'add');
Run Code Online (Sandbox Code Playgroud)
*更新2:Aaron Bertrand的评论启发的动态但非高效的方法*
这是Aaron在其评论中引用的方法中描述的方法的概念证明.(它在较大的数据集上执行可怕)
-- Inspired by Aaron Bertrand's comment
WITH [cte_KVP]
AS
(
-- Generating Key/Value pairs for columns in a table
-- Courtesey of Mikael Eriksson (http://stackoverflow.com/questions/7341143/flattening-of-a-1-row-table-into-a-key-value-pair-table/)
SELECT
[T2].[N].value(N'local-name(.)', N'sysname') AS [Key],
[T2].[N].value(N'.', N'nvarchar(max)') AS [Value],
[T2].[N].value(N'../GROUP[1]', N'int') AS [GROUP] -- 3. Used for to group the key/value pairs per row
FROM
(
SELECT
*,
ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [GROUP] -- 1. Generating a simple "identity" value.
FROM
@sample
FOR XML PATH(N'Row'), TYPE -- 2. Adding the 'Row' to the path separates each row, and allows us to backtrack via xpath to get the "GROUP" id
) AS [T1]([x])
CROSS APPLY
[T1].[x].nodes(N'Row/*') AS [T2]([N])
WHERE
[T2].[N].value(N'local-name(.)', N'sysname') <> N'GROUP'
)
SELECT
[InnerNodes].[xml] AS [*]
FROM
(
-- Probably preferable to use a table of numbers here
SELECT DISTINCT
[GROUP]
FROM
[cte_KVP]
) AS [Numbers]([Number])
CROSS APPLY
(
-- Generating the xml fragment specified by OP
SELECT
[cte_KVP].[Key] AS [@name],
[cte_KVP].[Value] AS [data()]
FROM
[cte_KVP]
WHERE
[cte_KVP].[GROUP] = [Numbers].[Number]
FOR XML PATH(N'field'), ROOT(N'doc'), TYPE
) AS [InnerNodes]([xml])
FOR XML PATH(N''), ROOT(N'add');
Run Code Online (Sandbox Code Playgroud)