由于在另一个重复模式中重复节点,在 PL/SQL 中提取部分 XMLType

Posted

技术标签:

【中文标题】由于在另一个重复模式中重复节点,在 PL/SQL 中提取部分 XMLType【英文标题】:Extracting part of XMLType in PL/SQL because of repeating node inside another repeating mode 【发布时间】:2013-08-26 13:20:33 【问题描述】:

我有一个 XMLType 对象,我想将开放时间提取到表中。

<workspace>
  <title>workspace1</title>
  <item>
    <day>1</day>
    <openingTime>8:00</openingTime>
    <closingTime>12:00</closingTime>
  </item>
  <item>
    <day>1</day>
    <openingTime>13:00</openingTime>
    <closingTime>18:00</closingTime>
  </item>
<workspace>
<workspace>
  <title>workspace2</title>
  <item>
    <day>1</day>
    <openingTime>9:00</openingTime>
    <closingTime>14:00</closingTime>
  </item>
  <item>
    <day>3</day>
    <openingTime>12:00</openingTime>
    <closingTime>16:00</closingTime>
  </item>
<workspace>

我会使用类似的东西:

SELECT ExtractValue(Value(p),'workspace/item/day/text()') as day
      ,ExtractValue(Value(p),'workspace/item/openingTime/text()') as open
      ,ExtractValue(Value(p),'workspace/item/closingTime/text()') as close
      FROM TABLE (XMLSequence(Extract(y,'workspace'))) p
      WHERE ExtractValue(Value(p),'/workspace/title/text()') LIKE 'workspace1';

其中 y 是上面的 XMLType。但这不起作用,因为它仍然会找到多个 item 节点。我需要提取标题工作区 2 的所有元素值(值 1、9:00、14:00、3、12:00、16:00)。如果我不仅可以提取值,而且可以提取 XMLType 的整个部分,那将会有所帮助。有任何想法吗? 谢谢,迈克尔

【问题讨论】:

【参考方案1】:

您的目标可以通过使用XMLTable 来实现:

with x as ( -- Just to introduce XML parameter
  select 
    xmltype('
       <workspace_list>     
        <workspace>
          <title>workspace1</title>
          <item>
            <day>1</day>
            <openingTime>8:00</openingTime>
            <closingTime>12:00</closingTime>
          </item>
          <item>
            <day>1</day>
            <openingTime>13:00</openingTime>
            <closingTime>18:00</closingTime>
          </item>
        </workspace>
        <workspace>
          <title>workspace2</title>
          <item>
            <day>1</day>
            <openingTime>9:00</openingTime>
            <closingTime>14:00</closingTime>
          </item>
          <item>
            <day>3</day>
            <openingTime>12:00</openingTime>
            <closingTime>16:00</closingTime>
          </item>
        </workspace>
       </workspace_list>     
  ') xfield
  from dual
)  
select 
  workspace, day, opening_time, closing_time
from
 XMLTable(
   '
     for $i in $doc//workspace[title eq $workspace_filter]
     for $j in $i/item 
     return 
      <wks_item>
        <wks_name>$i/title/text()</wks_name> 
        $j/*
      </wks_item> 
   '
   passing 
    (select xfield from x) as "doc",
    ('workspace1')         as "workspace_filter"
   columns
   workspace     varchar2(100) path '//wks_name',
   day           varchar2(100) path '//day',
   opening_time  varchar2(100) path '//openingTime',
   closing_time  varchar2(100) path '//closingTime'
 )

SQLFiddle Example

请注意,我引入了 &lt;workspace_list&gt; 顶部元素并添加了斜线以关闭 &lt;workspace&gt; 元素以使 XML 有效。

【讨论】:

【参考方案2】:

使用一些@ThinkJet 技巧,您的查询可能看起来像这样

with x as (
  select 
    xmltype('
       <workplaces>     
        <workspace>
          <title>workspace1</title>
          <item>
            <day>1</day>
            <openingTime>8:00</openingTime>
            <closingTime>12:00</closingTime>
          </item>
          <item>
            <day>1</day>
            <openingTime>13:00</openingTime>
            <closingTime>18:00</closingTime>
          </item>
        </workspace>
        <workspace>
          <title>workspace2</title>
          <item>
            <day>1</day>
            <openingTime>9:00</openingTime>
            <closingTime>14:00</closingTime>
          </item>
          <item>
            <day>3</day>
            <openingTime>12:00</openingTime>
            <closingTime>16:00</closingTime>
          </item>
        </workspace>
       </workplaces>     
  ') xfield
  from dual
)
SELECT "day", "openingTime", "closingTime"
FROM xmltable('$doc//workspace[title=$workspace_filter]/item'
              passing (select xfield from x) as "doc",
                      ('workspace1') as "workspace_filter"
               columns "openingTime" path '//openingTime',
                       "closingTime" path '//closingTime',
                       "day" path '//day')

【讨论】:

我在你的和@ThinkJet 解决方案之间使用了一些东西,但这需要相当长的时间(大约 6 分钟)。但我正在通过 Web 服务读取相当大的 XML 文件(cca 8 MB),所以也许这不是解决方案的错误 仔细想想,一点也不慢,8MB 6 分钟快得要死

以上是关于由于在另一个重复模式中重复节点,在 PL/SQL 中提取部分 XMLType的主要内容,如果未能解决你的问题,请参考以下文章

用于重复检查的动态 SQL - Oracle PL/SQL

并行执行 oracle PL/SQL [重复]

PL/SQL 逗号分隔列表;删除重复并放入数组

不要在游标 PL/SQL 中显示重复值

在pl sql中的单个变量中传递两个或多个参数[重复]

PL/SQl,oracle 9i,使用sql删除重复行