从MSSQL的XML列中提取xml标记数据

时间:2019-06-06 05:46:34

标签: sql sql-server xml

像我之前的问题一样,我想通过sql查询提取所有“名称”和路径标记(privilegedUsers->条目->条目->名称)。 谢谢

<Policy>
 <id>f3d25685-fb54-438d-a0e9-03e4ba5b555f</id>
 <name>SG</name>
 <description />
 <attributes>0</attributes>
 <parentPolicy>a7c603c0-8700-45ef-9165-c0134e292ee4</parentPolicy>
 <sharedPasswordRev>-1</sharedPasswordRev>
 <useShortChallengeResponse>false</useShortChallengeResponse>
 <settings>
 <privilegedUsers>
 <entries>
  <entry>
   <name>CEO</name>
   <path>CN=CEO,CN=Users,DC=sglab,DC=local</path>
   <uid>27C9C6AC9311424BB332CC5AB04B047D</uid>
   <serverName>192.168.7.201</serverName>
   <sid>S-1-5-21-3362085216-3357124804-2073486349-1108</sid>
   <type>user</type>
 </entry>
 <entry>
    <name>Administrator</name>
    <path>CN=Administrator,CN=Users,DC=sglab,DC=local</path>
    <uid>EBBC4D71CD68BE4BA49BC8B6DF01F954</uid>
    <serverName>192.168.7.201</serverName>
    <sid>S-1-5-21-3362085216-3357124804-2073486349-500</sid>
    <type>user</type>
   </entry>
 </privilegedUsers>
 <unknownAppsStrategy>EDITOR</unknownAppsStrategy>
</settings>
</Policy>

2 个答案:

答案 0 :(得分:0)

您的xml格式不正确。您没有结束</entries>标记。

修复后,这是您的代码:

declare @xml xml
set @xml=convert(xml,'<Policy>
 <id>f3d25685-fb54-438d-a0e9-03e4ba5b555f</id>
 <name>SG</name>
 <description />
 <attributes>0</attributes>
 <parentPolicy>a7c603c0-8700-45ef-9165-c0134e292ee4</parentPolicy>
 <sharedPasswordRev>-1</sharedPasswordRev>
 <useShortChallengeResponse>false</useShortChallengeResponse>
 <settings>
 <privilegedUsers>
 <entries>
  <entry>
   <name>CEO</name>
   <path>CN=CEO,CN=Users,DC=sglab,DC=local</path>
   <uid>27C9C6AC9311424BB332CC5AB04B047D</uid>
   <serverName>192.168.7.201</serverName>
   <sid>S-1-5-21-3362085216-3357124804-2073486349-1108</sid>
   <type>user</type>
 </entry>
 <entry>
    <name>Administrator</name>
    <path>CN=Administrator,CN=Users,DC=sglab,DC=local</path>
    <uid>EBBC4D71CD68BE4BA49BC8B6DF01F954</uid>
    <serverName>192.168.7.201</serverName>
    <sid>S-1-5-21-3362085216-3357124804-2073486349-500</sid>
    <type>user</type>
   </entry>
   </entries>
 </privilegedUsers>
 <unknownAppsStrategy>EDITOR</unknownAppsStrategy>
</settings>
</Policy>')

select @xml.query('/Policy/settings/privilegedUsers/entries/entry/name')

答案 1 :(得分:0)

您可以尝试

DECLARE @xml XML=
N'<Policy>
 <id>f3d25685-fb54-438d-a0e9-03e4ba5b555f</id>
 <name>SG</name>
 <description />
 <attributes>0</attributes>
 <parentPolicy>a7c603c0-8700-45ef-9165-c0134e292ee4</parentPolicy>
 <sharedPasswordRev>-1</sharedPasswordRev>
 <useShortChallengeResponse>false</useShortChallengeResponse>
 <settings>
 <privilegedUsers>
 <entries>
  <entry>
   <name>CEO</name>
   <path>CN=CEO,CN=Users,DC=sglab,DC=local</path>
   <uid>27C9C6AC9311424BB332CC5AB04B047D</uid>
   <serverName>192.168.7.201</serverName>
   <sid>S-1-5-21-3362085216-3357124804-2073486349-1108</sid>
   <type>user</type>
 </entry>
 <entry>
    <name>Administrator</name>
    <path>CN=Administrator,CN=Users,DC=sglab,DC=local</path>
    <uid>EBBC4D71CD68BE4BA49BC8B6DF01F954</uid>
    <serverName>192.168.7.201</serverName>
    <sid>S-1-5-21-3362085216-3357124804-2073486349-500</sid>
    <type>user</type>
   </entry>
 </entries>
 </privilegedUsers>
 <unknownAppsStrategy>EDITOR</unknownAppsStrategy>
</settings>
</Policy>';

-查询

SELECT @xml.value('(/Policy/id/text())[1]','uniqueidentifier') AS id
      ,@xml.value('(/Policy/name/text())[1]','nvarchar(max)') AS [name]
      --Use similar lines for all the other values below `<Policy>`
      ,prUsrEntry.value('(name/text())[1]','nvarchar(max)') AS PrivilegedUserName
      ,prUsrEntry.value('(path/text())[1]','nvarchar(max)') AS PrivilegedUserpath
      --Use similar lines for values within the given `<entry>`
FROM @xml.nodes('/Policy/settings/privilegedUsers/entries/entry') A(prUsrEntry);

简而言之:

我们直接调用.value(),以直接从@xml检索一级属性。使用nodes().query()可以避免重复的XPath,并且可能会更容易阅读,但这会降低性能。

然后,我们使用FROM @xml.nodes()获得派生的重复元素表。给定路径上的每个<entry>都将作为派生表中的一行返回,其中XML类型的列表示此路径上的<entry>

Wen现在可以使用.value()来读取嵌套的元素。请注意相对路径/前没有name)。

一些提示:

您的XML看起来好像它可能包含几个不同的<settings>。您可以使用这样的查询,使其更通用:

SELECT @xml.value('(/Policy/id/text())[1]','uniqueidentifier') AS id
      ,@xml.value('(/Policy/name/text())[1]','nvarchar(max)') AS [name]
      --Use similar lines for all the other values below `<Policy>`
      ,prUsrEntry.value('(name/text())[1]','nvarchar(max)') AS PrivilegedUserName
      ,prUsrEntry.value('(path/text())[1]','nvarchar(max)') AS PrivilegedUserpath
      --Use similar lines for values within the given `<entry>`
FROM @xml.nodes('/Policy/settings') A(settings)
OUTER APPLY A.settings.nodes('privilegedUsers/entries/entry') B(prUsrEntry)
--Add more APPLYs to fetch values from other `<settings>` areas

甚至是这种完全通用的方法

SELECT @xml.value('(/Policy/id/text())[1]','uniqueidentifier') AS id
      ,@xml.value('(/Policy/name/text())[1]','nvarchar(max)') AS [name]
      --Use similar lines for all the other values below `<Policy>`
      ,anySeeting.value('local-name(.)','nvarchar(max)') AS SettingName
      ,anyValue.value('local-name(.)','nvarchar(max)') AS ValueName
      ,anyValue.value('text()[1]','nvarchar(max)') AS NestedValue
FROM @xml.nodes('/Policy/settings') A(settings)
OUTER APPLY A.settings.nodes('*') B(anySeeting)
OUTER APPLY B.anySeeting.nodes('entries/entry/*') AS C(anyValue)

更新

这是对表数据执行相同操作的方法:

SELECT YourXML.value('(/Policy/id/text())[1]','uniqueidentifier') AS id
      ,YourXML.value('(/Policy/name/text())[1]','nvarchar(max)') AS [name]
      --Use similar lines for all the other values below `<Policy>`
      ,prUsrEntry.value('(name/text())[1]','nvarchar(max)') AS PrivilegedUserName
      ,prUsrEntry.value('(path/text())[1]','nvarchar(max)') AS PrivilegedUserpath
      --Use similar lines for values within the given `<entry>`
FROM YourTable
OUTER APPLY YourXML.nodes('/Policy/settings/privilegedUsers/entries/entry') A(prUsrEntry);