来自多个元素的Oracle SQL extractvalue

时间:2014-01-19 15:13:35

标签: sql oracle plsql xml-parsing oracle-xml-db

我花了几天时间寻找以下问题的简单解决方案,我需要一些帮助。我有一个带有两列的Oracle表,recid(帐号)作为主键,xmlrecord存储所有xml数据。我试图使用SQL查询为我们的应用程序导出具有多值项的值。排除数据损坏,如果存在c1 m =“1”,则总会有相应的c2 m =“1”和c3 m =“1”,依此类推。该表太大而无法多次触发它以提取每个项目,因此我需要在行的一次访问中将它们全部拉出xmlrecord。我已经尝试了内部联接(1 = 1)和xmltables,但总是在返回的数据中使用NULLS或在新行上的每个新匹配。由于xml

的结构,在此实例中从顶层提取值不适用于我

我们的基表数据结构:

RECID             XMLRECORD
-----------------------------------
0000001           <row><c1>test</c1><c2>test2</c2>....</row>
0000002           <row><c1>test</c1><c2>test2</c2>....</row>

上述记录可以正常工作,因为没有多个valuse字段。我正在努力的地方是存储在XMLRecord中的数据如下所示:

<row>
  <c1>test1</c1>
  <c1 m=1>test1_2</c1>
  <c2>test2</c2>
  <c2 m=1>test2_2</c2>
  <c3>test3</c3>
  <c3 m=1>test3_2</c3>
</row>

我想要的输出格式如下:

RECID       Col1     Col2     Col3
-----------------------------------
0000003     test1    test2    test3
0000003     test1_2  test2_2  test3_2
0000004     test1    test2    test3
0000004     test1_2  test2_2  test3_2   

2 个答案:

答案 0 :(得分:1)

谢谢你的评论,但我已经设法通过构建一个适用于此实例的连接来获得我需要的解决方案。关于它的好处是,无论供应商向我们投放多少记录,它都会起作用。在某些情况下,“m”属性最多可达9或10。

我在(1 = 1)上使用了通常的内部联接,并基于动态ID构建了后续联接。 第一行的ID_NUM的结果是“c”,下一行是“c2”,依此类推。

SELECT 
    t.recid
    ,t2.VALUE1 
    ,t3.VALUE2 
    ,t4.VALUE3 
FROM t
INNER JOIN XMLTABLE('/row/c1'
    PASSING t.xmlrecord
    ID_NUM VARCHAR(4) path 'concat(substring(ancestor-or-self::*/name(.),1,1), @m)',
    VALUE1 VARCHAR(20) path '.') t2
ON (1=1)
INNER JOIN XMLTABLE('/row/c2'
    PASSING t.xmlrecord
    ID_NUM VARCHAR(4) path 'concat(substring(ancestor-or-self::*/name(.),1,1), @m)',
    VALUE2 VARCHAR(20) path '.') t3
ON (t2.ID_NUM=t3.ID_NUM)
INNER JOIN XMLTABLE('/row/c3'
    PASSING t.xmlrecord
    ID_NUM VARCHAR(4) path 'concat(substring(ancestor-or-self::*/name(.),1,1), @m)',
    VALUE3 VARCHAR(20) path '.') t4
ON (t2.ID_NUM=t4.ID_NUM)

答案 1 :(得分:0)

您应该能够使用EXTRACTVALUE()和XPATH查询,该查询根据属性选择元素,如此。

SELECT RECID
     , EXTRACTVALUE(XMLRECORD, '/row/c1[@m=''1'']')
     , EXTRACTVALUE(XMLRECORD, '/row/c2[@m=''1'']')
     , EXTRACTVALUE(XMLRECORD, '/row/c3[@m=''1'']')
 FROM T

然后你可以用

UNION ALL这个结果
SELECT RECID
     , EXTRACTVALUE(XMLRECORD, '/row/c1[not(@m)]')
     , EXTRACTVALUE(XMLRECORD, '/row/c2[not(@m)]')
     , EXTRACTVALUE(XMLRECORD, '/row/c3[not(@m)]')
 FROM T

您可以继续使用UNIONS获取具有多个属性的可能行数。

我不认为在表的一次完整扫描中这很容易,因为您试图为您选择的每一行生成多行。

这是为什么在关系数据库中存储XML的一个很好的例子。

我正在尝试用XMLTABLE来实现这个目的,如果我想到一种方法,我会更新答案。