Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 通过XQuery将嵌套XML转换为平面XML_Sql_Xml_Xquery - Fatal编程技术网

Sql 通过XQuery将嵌套XML转换为平面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

我有一段嵌套的XML要插入到SQL中

导入XML:

 <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