【问题标题】:How to retrieve a value from key value pair in XML via SQL Query?如何通过 SQL Query 从 XML 中的键值对中检索值?
【发布时间】:2019-05-27 06:05:28
【问题描述】:

我的数据库表中有一个带有名称属性的列,它是一个存储 XML 数据的 clob 对象,如下所示。使用 SQL,我试图检索键 accountExpires 的值,这应该给我 123456789L 的值作为输出。

我尝试使用节点(Xquery) 和 CROSS APPLY 等,但我只获取通常采用值格式的那些,例如 IIQDisabledaccountFlags 等,但我想检索条目键和值对。感谢你的帮助。

<Attributes>
  <Map>
    <entry key="Division" value="TRAINING"/>
    <entry key="IIQDisabled">
      <value>
        <Boolean>true</Boolean>
      </value>
    </entry>
    <entry key="accountExpires" value="123456789L"/>
    <entry key="accountFlags">
      <value>
        <List>
          <String>Normal User Account</String>
          <String>User Account is Disabled</String>
        </List>
      </value>
    </entry>
    <entry key="department" value="LOYALTY CLUB"/>
    <entry key="distinguishedName" value="CN=Account02\,TM_Test02,OU=SailpointQA,OU=Users...."/>
    <entry key="employeeID" value="333223"/>
    <entry key="givenName" value="TM_Test02"/>
    <entry key="memberOf"/>
    <entry key="mobile" value="9"/>
    <entry key="sAMAccountName" value="TM_Test02.Account02"/>
    <entry key="sAMAccountType" value="805306368"/>
    <entry key="sn" value="Account02"/>
    <entry key="userAccountControl" value="514"/>
  </Map>
</Attributes>


select a.id as id
,pref.value('(@accountExpires)[1]', 'varchar(50)') as accountExpires
,pref.value('.', 'varchar(50)') as test
FROM (
select  
         id,CONVERT(XML, attributes, 1) xmlCol 
from [identityiq].[identityiq].[spt_work_item_archive]) a 
CROSS APPLY xmlCol.nodes('//Attributes/Map') AS ApprovalItem(pref)

预期结果:

id       accountExpires
-----------------
someid   123456789L

但实际上,如果使用 pref.value('.', 'varchar( 50)') 在输出中作为测试列。

【问题讨论】:

  • 您好,只是为了保持整洁:您已用[sql-server] 标记了这个问题,但接受了[oracle] 的答案。这不会帮助未来的访问者试图找到答案。请将问题的标签更改为[oracle] 或接受现有的[sql-server] 相关答案(或编写您自己的答案并接受...)

标签: sql sql-server xml


【解决方案1】:

根据您自己的代码,我认为这是 SQL-Server。至少语法是这样的。

你可以试试这个:

DECLARE @xml XML=
N'<Attributes>
  <Map>
    <entry key="Division" value="TRAINING"/>
    <entry key="IIQDisabled">
      <value>
        <Boolean>true</Boolean>
      </value>
    </entry>
    <entry key="accountExpires" value="123456789L"/>
    <entry key="accountFlags">
      <value>
        <List>
          <String>Normal User Account</String>
          <String>User Account is Disabled</String>
        </List>
      </value>
    </entry>
    <entry key="department" value="LOYALTY CLUB"/>
    <entry key="distinguishedName" value="CN=Account02\,TM_Test02,OU=SailpointQA,OU=Users...."/>
    <entry key="employeeID" value="333223"/>
    <entry key="givenName" value="TM_Test02"/>
    <entry key="memberOf"/>
    <entry key="mobile" value="9"/>
    <entry key="sAMAccountName" value="TM_Test02.Account02"/>
    <entry key="sAMAccountType" value="805306368"/>
    <entry key="sn" value="Account02"/>
    <entry key="userAccountControl" value="514"/>
  </Map>
</Attributes>';

--查询

SELECT entr.value('@key','nvarchar(100)') AS AttrKey
      ,entr.value('@value','nvarchar(500)') AS AttrValue
      ,HasValueElement.value('local-name(.)','nvarchar(100)') AS ValueType
      ,HasValueElement.value('text()[1]','nvarchar(500)') AS ValueTypeValue
      ,IsAList.value('local-name(.)','nvarchar(100)') AS ListValueType
      ,IsAList.value('text()[1]','nvarchar(500)') AS ListValueValue

FROM @xml.nodes(N'/Attributes/Map/entry') A(entr)
OUTER APPLY A.entr.nodes(N'value/*') B(HasValueElement)
OUTER APPLY B.HasValueElement.nodes('*') C(IsAList);

结果

+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| Division           | TRAINING                                            |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| IIQDisabled        | NULL                                                | Boolean | true |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| accountExpires     | 123456789L                                          |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| accountFlags       | NULL                                                | List    | NULL | String | Normal User Account      |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| accountFlags       | NULL                                                | List    | NULL | String | User Account is Disabled |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| department         | LOYALTY CLUB                                        |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| distinguishedName  | CN=Account02\,TM_Test02,OU=SailpointQA,OU=Users.... |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| employeeID         | 333223                                              |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| givenName          | TM_Test02                                           |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| memberOf           | NULL                                                |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| mobile             | 9                                                   |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| sAMAccountName     | TM_Test02.Account02                                 |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| sAMAccountType     | 805306368                                           |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| sn                 | Account02                                           |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+
| userAccountControl | 514                                                 |         | NULL |        | NULL                     |
+--------------------+-----------------------------------------------------+---------+------+--------+--------------------------+

一些解释:

数据分为三种:

  1. 简单的键值对
  2. 键入的键值对
  3. 类型化列表值

查询将使用.nodes() 深入了解所有&lt;entry&gt; 元素并将它们作为派生表返回。第一个OUTER APPLY 将在给定&lt;entry&gt; 下方有&lt;value&gt; 元素的情况下返回额外的行/列。这个元素可能有一个值(如布尔值“true”),或者它可能包含一个类型列表。第二个OUTER APPLY 潜入(如果存在)进入&lt;value&gt; 的子节点并将它们作为附加行返回。

这样的查询会以 EAV 样式返回更多

SELECT entr.value('@key','nvarchar(100)') AS AttrKey
      ,COALESCE(entr.value('@value','nvarchar(500)'),HasValueElement.value('text()[1]','nvarchar(500)'),IsAList.value('text()[1]','nvarchar(500)')) AS AttrValue
      ,HasValueElement.value('local-name(.)','nvarchar(100)') AS ValueType
      ,IsAList.value('local-name(.)','nvarchar(100)') AS ListValueType

FROM @xml.nodes(N'/Attributes/Map/entry') A(entr)
OUTER APPLY A.entr.nodes(N'value/*') B(HasValueElement)
OUTER APPLY B.HasValueElement.nodes('*') C(IsAList);

结果

+--------------------+-----------------------------------------------------+-----------+---------------+
| AttrKey            | AttrValue                                           | ValueType | ListValueType |
+--------------------+-----------------------------------------------------+-----------+---------------+
| Division           | TRAINING                                            |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| IIQDisabled        | true                                                | Boolean   |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| accountExpires     | 123456789L                                          |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| accountFlags       | Normal User Account                                 | List      | String        |
+--------------------+-----------------------------------------------------+-----------+---------------+
| accountFlags       | User Account is Disabled                            | List      | String        |
+--------------------+-----------------------------------------------------+-----------+---------------+
| department         | LOYALTY CLUB                                        |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| distinguishedName  | CN=Account02\,TM_Test02,OU=SailpointQA,OU=Users.... |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| employeeID         | 333223                                              |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| givenName          | TM_Test02                                           |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| memberOf           | NULL                                                |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| mobile             | 9                                                   |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| sAMAccountName     | TM_Test02.Account02                                 |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| sAMAccountType     | 805306368                                           |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| sn                 | Account02                                           |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+
| userAccountControl | 514                                                 |           |               |
+--------------------+-----------------------------------------------------+-----------+---------------+

【讨论】:

  • 完美!这就是我要找的。感谢您的时间和详细的解释。
【解决方案2】:

您可以尝试使用 EXTRACTVALUE 函数和 XPATH

SELECT EXTRACTVALUE( xmlCol,  '//Map/entry [@key='accountExpires']/@value')

  AS accountExpires

from [identityiq].[identityiq].[spt_work_item_archive]) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 2023-04-04
    • 2020-08-19
    相关资源
    最近更新 更多