Sql 通过XQuery将嵌套XML转换为平面XML
我有一段嵌套的XML要插入到SQL中 导入XML:Sql 通过XQuery将嵌套XML转换为平面XML,sql,xml,xquery,Sql,Xml,Xquery,我有一段嵌套的XML要插入到SQL中 导入XML: <RECORD> <RECID>118810</RECID> <FIELD TYPE="C"> <NAME>proj_code</NAME> <VALUE>118810</VALUE> </FIELD> <FIELD TYPE="C"> <NAM
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
118810
项目代码
118810
分包商
99900
项目说明
2018年纳吉科门科斯滕啤酒节
专业统计
9
评论
我想通过XQuery将其转换为:
<RECORD>
<RECID>118810</RECID>
<proj_code>118810</proj_code>
<sub_nr>99900</sub_nr>
<proj_desc>Nagekomen kosten Oktober 2018</proj_desc>
<pro_stat>9</pro_stat>
<comment></comment>
</RECORD>
118810
118810
99900
2018年纳吉科门科斯滕啤酒节
9
所以我可以将它导入SQL
有什么想法吗 只需将每个
记录
映射到一个新记录,在该记录中将所有字段
映射到元素,元素的名称来自name,值来自value:
RECORD !
<RECORD>
{
RECID,
FIELD ! element { NAME } { data(VALUE) }
}
</RECORD>
我试过这个:
DECLARE @xml xml;
SET @xml =N'
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
<RECORD>
<RECID>118811</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118811</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten November 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
';
SELECT @xml.query('
for $record in //RECORD
return
<RECORD>
{
$record/RECID,
for $field in $record/FIELD
return element { $field/NAME } { data($field/VALUE) }
}
</RECORD>
' ) as result
DECLARE@xml;
设置@xml=N'
118810
项目代码
118810
分包商
99900
项目说明
2018年纳吉科门科斯滕啤酒节
专业统计
9
评论
118811
项目代码
118811
分包商
99900
项目说明
纳吉科门科斯滕2018年11月
专业统计
9
评论
';
选择@xml.query('
在//record中的$record
返回
{
$record/RECID,
对于$record/字段中的$field
返回元素{$field/NAME}{data($field/VALUE)}
}
""因此,
但是我在返回元素部分得到一个错误:
XQuery[query()]:计算元素和属性构造函数的名称表达式只支持常量表达式。正如Martin Honnen指出的,MS SQL Server XQuery不支持计算动态元素名,只支持文本。不幸的是,甚至包括最新的SQL Server 2019。这是一个丑陋的解决方案 SQL
DECLARE@xml=N'
118810
项目代码
118810
分包商
99900
项目说明
2018年纳吉科门科斯滕啤酒节
专业统计
9
评论
118811
项目代码
118811
分包商
99901
项目说明
纳吉科门科斯滕2019年11月
专业统计
19
评论
哇!
';
声明@tbl表(ID INT-IDENTITY(1,1)主键,RECID-VARCHAR(10),[col_-name]VARCHAR(20),[col_-value]VARCHAR(100));
插入@tbl
选择c.value(“(../RECID/text())[1]”,“VARCHAR(100)”作为[RECID]
,c.value('(NAME/text())[1],'VARCHAR(30)'作为[NAME]
,c.value('(value/text())[1],'VARCHAR(100)'作为[value]
从@xml.nodes('root/RECORD/FIELD')中取t(c);
声明@rowcountint=(从@tbl中选择MAX(ID)
,@recID varchar(10)=(从@tbl中选择TOP(1)recID,其中ID=1)
,@xml_data VARCHAR(MAX)='';
当@RowCount>0开始时
选择@xml_data+=IIF(@recID!=recID,,'')+
--''+聚结([col_值],'')+''
CONCAT(“”,[col_值],“”)
,@recID=recID
来自@tbl
ORDER BY ID DESC OFFSET@RowCount-1行仅取下1行;
设置@RowCount-=1;
结束;
设置@xml_data+='';
选择CAST(@xml_data AS xml);
这是最终版本,带有用于将其插入SQL的select:
DECLARE @xml XML = N'
<AVXML>
<SIGNONMSGRS>
<DTSERVER>2019-09-10T15:54:32</DTSERVER>
<APPID>ACCOUNTVIEW</APPID>
<APPVER>0908-</APPVER>
</SIGNONMSGRS>
<EBUSMSGSRS>
<EBUSQRYRS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
<RECORD>
<RECID>118811</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118811</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99901</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten November 2019</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>19</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE>wow</VALUE>
</FIELD>
</RECORD>
</EBUSQRYRS>
</EBUSMSGSRS>
</AVXML>
';
DECLARE @tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, RECID VARCHAR(10), [col_name] VARCHAR(20), [col_value] VARCHAR(100));
INSERT INTO @tbl
SELECT c.value('(../RECID/text())[1]', 'VARCHAR(100)') AS [RECID]
, c.value('(NAME/text())[1]', 'VARCHAR(30)') AS [name]
, c.value('(VALUE/text())[1]', 'VARCHAR(500)') AS [value]
FROM @xml.nodes('//RECORD/FIELD') AS t(c);
DECLARE @RowCount INT = (SELECT MAX(ID) FROM @tbl)
, @recID varchar(10) = (SELECT TOP(1) RECID FROM @tbl WHERE ID = 1)
, @xml_data VARCHAR(MAX) = '<root><RECORD>';
WHILE @RowCount > 0 BEGIN
SELECT @xml_data +=
IIF(@recID != RECID,
'<RECID>' + @recID + '</RECID>' +
'</RECORD><RECORD>',
'') +
CONCAT('<',[col_Name],'>',[col_value],'</',[col_Name],'>')
, @recID = RECID
FROM @tbl
ORDER BY ID DESC OFFSET @RowCount - 1 ROWS FETCH NEXT 1 ROWS ONLY;
SET @RowCount -= 1;
END;
SET @xml_data += '<RECID>' + @recID + '</RECID>' + '</RECORD></root>';
DECLARE @handler int;
exec sys.sp_xml_preparedocument @handler OUTPUT, @xml_data;
--print @xml_data
select *
from OPENXML(@handler,'/root/RECORD',11)
WITH
(
id nvarchar(50) 'RECID',
proj_code nvarchar(50) 'proj_code',
sub_nr nvarchar(50) 'sub_nr',
proj_desc nvarchar(1000) 'proj_desc',
pro_stat nvarchar(50) 'pro_stat',
comment nvarchar(50) 'comment'
)
exec sys.sp_xml_removedocument @handler
DECLARE@xml=N'
2019-09-10T15:54:32
ACCOUNTVIEW
0908-
118810
项目代码
118810
分包商
99900
项目说明
2018年纳吉科门科斯滕啤酒节
专业统计
9
评论
118811
项目代码
118811
分包商
99901
项目说明
纳吉科门科斯滕2019年11月
专业统计
19
评论
哇!
';
声明@tbl表(ID INT-IDENTITY(1,1)主键,RECID-VARCHAR(10),[col_-name]VARCHAR(20),[col_-value]VARCHAR(100));
插入@tbl
选择c.value(“(../RECID/text())[1]”,“VARCHAR(100)”作为[RECID]
,c.value('(NAME/text())[1],'VARCHAR(30)'作为[NAME]
,c.value('(value/text())[1],'VARCHAR(500)'作为[value]
从@xml.nodes('//RECORD/FIELD')作为t(c);
声明@rowcountint=(从@tbl中选择MAX(ID)
,@recID varchar(10)=(从@tbl中选择TOP(1)recID,其中ID=1)
,@xml_data VARCHAR(MAX)='';
当@RowCount>0开始时
选择@xml_data+=
IIF(@recID!=recID,
“+@recID+”+
'',
'') +
CONCAT(“”,[col_值],“”)
,@recID=recID
来自@tbl
ORDER BY ID DESC OFFSET@RowCount-1行仅取下1行;
设置@RowCount-=1;
结束;
设置@xml_data+='+@recID+'+'';
声明@handler int;
exec sys.sp_xml_preparedocument@handler OUTPUT,@xml_data;
--打印@xml\u数据
挑选*
来自OPENXML(@handler,'/root/RECORD',11)
具有
(
id nvarchar(50)“RECID”,
项目代码nvarchar(50)‘项目代码’,
nvarchar分包商(50)‘分包商’,
项目说明nvarchar(1000)“项目说明”,
专业统计数据nvarchar(50)‘专业统计数据’,
评论nvarchar(50)‘评论’
)
exec sys.sp_xml_removedocument@handler
这似乎是对您的数据库系统(MS SQL server?)的XQuery子集的限制。如果有专门用于数据库系统和/或其XQuery sup的标记,那么让我们看看其他人是否可以在这方面提供帮助
DECLARE @xml XML = N'<root>
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
<RECORD>
<RECID>118811</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118811</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99901</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten November 2019</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>19</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE>wow</VALUE>
</FIELD>
</RECORD>
</root>';
DECLARE @tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, RECID VARCHAR(10), [col_name] VARCHAR(20), [col_value] VARCHAR(100));
INSERT INTO @tbl
SELECT c.value('(../RECID/text())[1]', 'VARCHAR(100)') AS [RECID]
, c.value('(NAME/text())[1]', 'VARCHAR(30)') AS [name]
, c.value('(VALUE/text())[1]', 'VARCHAR(100)') AS [value]
FROM @xml.nodes('root/RECORD/FIELD') AS t(c);
DECLARE @RowCount INT = (SELECT MAX(ID) FROM @tbl)
, @recID varchar(10) = (SELECT TOP(1) RECID FROM @tbl WHERE ID = 1)
, @xml_data VARCHAR(MAX) = '<root><RECORD>';
WHILE @RowCount > 0 BEGIN
SELECT @xml_data += IIF(@recID != RECID, '</RECORD><RECORD>', '') +
--'<' + [col_Name] + '>' + COALESCE([col_value],'') + '</' + [col_Name] + '>'
CONCAT('<',[col_Name],'>',[col_value],'</',[col_Name],'>')
, @recID = RECID
FROM @tbl
ORDER BY ID DESC OFFSET @RowCount - 1 ROWS FETCH NEXT 1 ROWS ONLY;
SET @RowCount -= 1;
END;
SET @xml_data += '</RECORD></root>';
SELECT CAST(@xml_data AS XML);
DECLARE @xml XML = N'
<AVXML>
<SIGNONMSGRS>
<DTSERVER>2019-09-10T15:54:32</DTSERVER>
<APPID>ACCOUNTVIEW</APPID>
<APPVER>0908-</APPVER>
</SIGNONMSGRS>
<EBUSMSGSRS>
<EBUSQRYRS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
<RECORD>
<RECID>118811</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118811</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99901</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten November 2019</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>19</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE>wow</VALUE>
</FIELD>
</RECORD>
</EBUSQRYRS>
</EBUSMSGSRS>
</AVXML>
';
DECLARE @tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, RECID VARCHAR(10), [col_name] VARCHAR(20), [col_value] VARCHAR(100));
INSERT INTO @tbl
SELECT c.value('(../RECID/text())[1]', 'VARCHAR(100)') AS [RECID]
, c.value('(NAME/text())[1]', 'VARCHAR(30)') AS [name]
, c.value('(VALUE/text())[1]', 'VARCHAR(500)') AS [value]
FROM @xml.nodes('//RECORD/FIELD') AS t(c);
DECLARE @RowCount INT = (SELECT MAX(ID) FROM @tbl)
, @recID varchar(10) = (SELECT TOP(1) RECID FROM @tbl WHERE ID = 1)
, @xml_data VARCHAR(MAX) = '<root><RECORD>';
WHILE @RowCount > 0 BEGIN
SELECT @xml_data +=
IIF(@recID != RECID,
'<RECID>' + @recID + '</RECID>' +
'</RECORD><RECORD>',
'') +
CONCAT('<',[col_Name],'>',[col_value],'</',[col_Name],'>')
, @recID = RECID
FROM @tbl
ORDER BY ID DESC OFFSET @RowCount - 1 ROWS FETCH NEXT 1 ROWS ONLY;
SET @RowCount -= 1;
END;
SET @xml_data += '<RECID>' + @recID + '</RECID>' + '</RECORD></root>';
DECLARE @handler int;
exec sys.sp_xml_preparedocument @handler OUTPUT, @xml_data;
--print @xml_data
select *
from OPENXML(@handler,'/root/RECORD',11)
WITH
(
id nvarchar(50) 'RECID',
proj_code nvarchar(50) 'proj_code',
sub_nr nvarchar(50) 'sub_nr',
proj_desc nvarchar(1000) 'proj_desc',
pro_stat nvarchar(50) 'pro_stat',
comment nvarchar(50) 'comment'
)
exec sys.sp_xml_removedocument @handler