Sql server 用T-SQL分解XML-What';从组内提取行值的正确语法是什么?
我正在尝试使用一些以XML形式接收的日志数据 我在SQL Server中获得了XML数据包,在清理数据以使其成为有效的XML之后。(并从JSON包装中获取其他属性,等等) 但现在我一直在尝试读取XML以从单独的行中检索值 我的示例XML如下所示:Sql server 用T-SQL分解XML-What';从组内提取行值的正确语法是什么?,sql-server,xml,tsql,Sql Server,Xml,Tsql,我正在尝试使用一些以XML形式接收的日志数据 我在SQL Server中获得了XML数据包,在清理数据以使其成为有效的XML之后。(并从JSON包装中获取其他属性,等等) 但现在我一直在尝试读取XML以从单独的行中检索值 我的示例XML如下所示: <?xml version="1.0" encoding="UTF-8"?> <general> <group id="0" comment="A
<?xml version="1.0" encoding="UTF-8"?>
<general>
<group id="0" comment="Application">
<N1 comment="Start Date">2020-11-03T00:05:48Z</N1>
<N2 comment="Name/Description">ProgramName</N2>
<N3 comment="Version Number">ReleaseNumber</N3>
<N5 comment="Compilation Date">2020-10-01T01:05:01Z</N5>
<N6 comment="Up Time">1899-12-30T00:00:56Z</N6>
</group>
<group id="1" comment="Exception">
<N1 comment="Date">Tue, 3 Nov 2020 11:06:45 +1100</N1>
<N2 comment="Address">MemoryAddress</N2>
<N3 comment="Module Name">ModuleName</N3>
<N4 comment="Module Version">ModuleVersionNumber</N4>
<N5 comment="Type">ExceptionType</N5>
<N6 comment="Message">Insufficient memory for this operation.</N6>
<N7 comment="ID">ExceptionID</N7>
<N8 comment="Count">1</N8>
<N9 comment="Status">New</N9>
<N11 comment="Sent">0</N11>
</group>
</general>
但是我不能用必要的XQuery/XPath来提取特定编号组中的子行的值
@X.value('(/log/group[1]/N2)[1]','VARCHAR(50)') ,10)
任何人都可以分享从N2查询值的魔力吗?我怀疑答案在Contains中,但我在寻找编写代码教程以使指令在我的脑海中快速就位时遇到了问题。
(这很复杂,因为我想从XML中的3个不同组中提取10个值。要查询我正在接收的日志的不同版本(我将其分解为一个平面文件以便提取属性),我最终运行了:
,ExceptionAddress=LEFT(@X.value('(/Doc/Log/General/Line_2.2/@Value)[1]','VARCHAR(10)') ,10)
,ExceptionType=LEFT(@X.value('(/Doc/Log/General/Line_2.5/@Value)[1]','VARCHAR(50)') ,50)
,ExceptionMessage=LEFT(@X.value('(/Doc/Log/General/Line_2.6/@Value)[1]','NVARCHAR(200)') ,200)
,FormClass=LEFT(@X.value('(/Doc/Log/General/Line_4.1/@Value)[1]','VARCHAR(50)') ,50)
,FormText=LEFT(@X.value('(/Doc/Log/General/Line_4.2/@Value)[1]','NVARCHAR(50)') ,50)
,ControlClass=LEFT(@X.value('(/Doc/Log/General/Line_4.3/@Value)[1]','VARCHAR(50)') ,50)
,ControlText=LEFT(@X.value('(/Doc/Log/General/Line_4.4/@Value)[1]','NVARCHAR(50)') ,50)
,OSType=LEFT(@X.value('(/Doc/Log/General/Line_6.1/@Value)[1]','VARCHAR(50)') ,50)
,OSBuild=LEFT(@X.value('(/Doc/Log/General/Line_6.2/@Value)[1]','VARCHAR(50)') ,50)
,OSUpdate=LEFT(@X.value('(/Doc/Log/General/Line_6.3/@Value)[1]','VARCHAR(50)') ,50)
好的,我已经找到了一个可能的解决办法 如果这个问题的措辞对其他人有帮助,我的解决方案是:
,LEFT(@X.value('(/log/general/group[1]/N6)[1]','VARCHAR(50)') ,50) --Find first GROUP, returend first result for N6
,LEFT(@X.value('(/log/general/group[@id="0"]/N6)[1]','VARCHAR(50)') ,50) --Find group with ID=0, return first result for N6
,LEFT(@X.value('(/log/general/group[@id="1"]/N6)[1]','VARCHAR(50)') ,50) --Find group with ID=1, reture first result for N6
,LEFT(@X.value('(/log/general/group[2]/N2)[1]','VARCHAR(50)') ,50) --Find second GROUP, returend first result for N6
注意,《红门简单对话》这篇文章给了我很大的启发,它的文章最终让我点击了一下
但是,如果有人有其他更好的解决方案,我们非常希望看到它们。您的XML在许多方面都有缺陷,这就是为什么没有简单而俗气的答案的原因: --这将尝试以表格格式获取EAV数据
SELECT A.gr.value('@id','int') groupId
,A.gr.value('@comment','nvarchar(max)') groupComment
,A.gr.value('(*[@comment="Compilation Date"])[1]','datetime') NCompilationDate
,A.gr.value('(*[@comment="Date"])[1]','nvarchar(max)') NDate
,A.gr.value('(*[@comment="Count"])[1]','int') NCount
FROM @xml.nodes('/general/group') A(gr);
为什么您的XML有缺陷:
- 您不应命名数字元素(N1、N2、N3…)。它们都应具有相同的名称。如果确实需要数字,请添加属性(
)nmbr=“1”
- 您正在混合日期-时间格式。在XML中,您应该只使用ISO8601(就像在第一组中一样)。最糟糕的情况是依赖于文化和语言的内容。在我的(德语)系统中,星期二的“Tue”将打破这一点
DECLARE @xml XML=
'<general>
<group id="0" comment="Application">
<N1 comment="Start Date">2020-11-03T00:05:48Z</N1>
<N2 comment="Name/Description">ProgramName</N2>
<N3 comment="Version Number">ReleaseNumber</N3>
<N5 comment="Compilation Date">2020-10-01T01:05:01Z</N5>
<N6 comment="Up Time">1899-12-30T00:00:56Z</N6>
</group>
<group id="1" comment="Exception">
<N1 comment="Date">Tue, 3 Nov 2020 11:06:45 +1100</N1>
<N2 comment="Address">MemoryAddress</N2>
<N3 comment="Module Name">ModuleName</N3>
<N4 comment="Module Version">ModuleVersionNumber</N4>
<N5 comment="Type">ExceptionType</N5>
<N6 comment="Message">Insufficient memory for this operation.</N6>
<N7 comment="ID">ExceptionID</N7>
<N8 comment="Count">1</N8>
<N9 comment="Status">New</N9>
<N11 comment="Sent">0</N11>
</group>
</general>';
SELECT A.gr.value('@id','int') groupId
,A.gr.value('@comment','nvarchar(max)') groupComment
,B.nd.value('@comment','nvarchar(max)') NComment
,B.nd.value('text()[1]','nvarchar(max)') NContent
FROM @xml.nodes('/general/group') A(gr)
OUTER APPLY A.gr.nodes('*') B(nd);
SELECT A.gr.value('@id','int') groupId
,A.gr.value('@comment','nvarchar(max)') groupComment
,A.gr.value('(*[@comment="Compilation Date"])[1]','datetime') NCompilationDate
,A.gr.value('(*[@comment="Date"])[1]','nvarchar(max)') NDate
,A.gr.value('(*[@comment="Count"])[1]','int') NCount
FROM @xml.nodes('/general/group') A(gr);