【问题标题】:ExtractXML Oracle Query Returns NullExtractXML Oracle 查询返回 Null
【发布时间】:2017-12-08 14:50:28
【问题描述】:

我在 Oracle 12c 数据库的“数据”表的“属性”列中有以下数据:

<Attributes>
  <Map>
    <entry key="accountFlags">
      <value>
        <List>
          <String>Normal User Account</String>
        </List>
      </value>
    </entry>
    <entry key="cn" value="paul.john"/>
    <entry key="department" value="IT"/>
    <entry key="description" value="New account. Automatically created"/>
    <entry key="displayName" value="John, Paul"/>
    <entry key="distinguishedName" value="CN=paul.john,OU=Users,DC=test,DC=com"/>
    <entry key="givenName" value="Paul"/>
    <entry key="homeMDB" value="CN=Test,CN=Databases,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=test,DC=com"/>
    <entry key="l" value="London"/>
    <entry key="mail" value="paul.john@test.com"/>
    <entry key="mailNickname" value="PaulJ"/>
    <entry key="manager" value="CN=brock.lesnar,OU=Users,DC=test,DC=com"/>
    <entry key="memberOf">
      <value>
        <List>
          <String>CN=Test1,OU=Rights,OU=Groups,DC=test,DC=com</String>
          <String>CN=Test2,OU=Rights,OU=Groups,DC=test,DC=com</String>
          <String>CN=Test3,OU=Rights,OU=Groups,DC=test,DC=com</String>
          <String>CN=Test4,OU=Rights,OU=Groups,DC=test,DC=com</String>
        </List>
      </value>
    </entry>
  </Map>
</Attributes>

我希望从该列中提取“memberOf”的值,如下所示:

MEMBER_OF
---------
CN=Test1,OU=Rights,OU=Groups,DC=test,DC=com
CN=Test2,OU=Rights,OU=Groups,DC=test,DC=com
CN=Test3,OU=Rights,OU=Groups,DC=test,DC=com
CN=Test4,OU=Rights,OU=Groups,DC=test,DC=com

我已尝试使用以下返回 null 的查询:

SELECT EXTRACTVALUE(xmltype(attributes), '/Attributes/Map/entry[@key="memberOf"]/value/List/@String')
FROM DATA;

我也试过下面的查询,它也返回 null

SELECT EXTRACTVALUE(xmltype(attributes), '/Attributes/Map/entry[@key="memberOf"]/value[1]/List/@String')
FROM DATA;

不确定是否需要在查询中传递其他内容?

【问题讨论】:

    标签: sql xml oracle


    【解决方案1】:

    您的路径以.../@String 结尾,它正在寻找一个名为String 的属性,而不是一个节点。但如果你修复它,你会得到:

    ORA-19025: EXTRACTVALUE returns value of only one node
    

    ExtractValue() is long-deprecated anyway。您可以改用 XMLQuery(),但这会为您提供单个 XML 片段而不是单独的字符串:

    select xmlquery('/Attributes/Map/entry[@key="memberOf"]/value/List/String'
      passing xmltype(attributes)
      returning content) as member_of
    from data;
    
    MEMBER_OF                                                                       
    --------------------------------------------------------------------------------
    <String>CN=Test1,OU=Rights,OU=Groups,DC=test,DC=com</String><String>CN=Test2,OU=
    Rights,OU=Groups,DC=test,DC=com</String><String>CN=Test3,OU=Rights,OU=Groups,DC=
    test,DC=com</String><String>CN=Test4,OU=Rights,OU=Groups,DC=test,DC=com</String>
    

    改为使用 XMLTable() 来获取单个值,正如 Bikash 建议的那样 - 但它可以更简单地完成,无需两次 XMLTable 调用:

    select x.member_of
    from data
    cross join XMLTable('/Attributes/Map/entry[@key="memberOf"]/value/List/String'
      passing XMLType(attributes)
      columns member_of varchar2(60) path '.'
    ) x;
    
    MEMBER_OF                                                   
    ------------------------------------------------------------
    CN=Test1,OU=Rights,OU=Groups,DC=test,DC=com
    CN=Test2,OU=Rights,OU=Groups,DC=test,DC=com
    CN=Test3,OU=Rights,OU=Groups,DC=test,DC=com
    CN=Test4,OU=Rights,OU=Groups,DC=test,DC=com
    

    Read more.


    如果您想在同一个查询中获取其他数据,您可以将它们添加为更多 columns 子句,参考备份树 - 因为其余的是单个节点,除非您有并且需要显示多个帐户标志。

    select x.*
    from data
    cross join XMLTable('/Attributes/Map/entry[@key="memberOf"]/value/List/String'
      passing XMLType(attributes)
      columns cn varchar2(20) path './../../../../entry[@key="cn"]/@value',
        department varchar2(10) path './../../../../entry[@key="department"]/@value',
        member_of varchar2(60) path '.'
    ) x;
    
    CN                   DEPARTMENT MEMBER_OF                                                   
    -------------------- ---------- ------------------------------------------------------------
    paul.john            IT         CN=Test1,OU=Rights,OU=Groups,DC=test,DC=com                 
    paul.john            IT         CN=Test2,OU=Rights,OU=Groups,DC=test,DC=com                 
    paul.john            IT         CN=Test3,OU=Rights,OU=Groups,DC=test,DC=com                 
    paul.john            IT         CN=Test4,OU=Rights,OU=Groups,DC=test,DC=com                 
    

    虽然这样做之后,如果您这样做使用多个 XMLTable 调用,可能会更容易阅读和维护:

    select x1.cn, x1.department, x2.member_of
    from data
    cross join XMLTable('/Attributes/Map'
      passing XMLType(attributes)
      columns cn varchar2(20) path 'entry[@key="cn"]/@value',
        department varchar2(10) path 'entry[@key="department"]/@value',
        member_of_xml XMLType path 'entry[@key="memberOf"]'
    ) x1
    cross join XMLTable('/entry/value/List/String'
      passing member_of_xml
      columns member_of varchar2(60) path '.'
    ) x2;
    

    添加第三个 XMLTable 调用来处理多个帐户标志很简单。

    您还可以在单​​个 XMLTable 中使用更复杂的 XPath 和循环等进行所有这些操作,但我认为这更清晰、更简单,除非您正在处理大型 XML 文档(以及很多文档)可能没有显着的性能差异。

    【讨论】:

    • 多么完整的答案!也很有见地!干杯!
    【解决方案2】:

    试试这个

    SELECT y.*
      FROM (SELECT *
              FROM XMLTABLE ('/Attributes/Map/entry[@key="memberOf"]/value/List'
                             PASSING (SELECT xmltype (attributes)
                                        FROM data)
                             COLUMNS strings XMLTYPE PATH 'String')) x,
           XMLTABLE ('/String'
                     PASSING x.strings
                     COLUMNS memberOf VARCHAR (300) PATH '.') y;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-02
      • 2013-04-28
      • 2019-06-14
      • 2020-01-07
      • 2015-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多