4

我花了几天时间寻找以下问题的简单解决方案,我需要一些帮助。我有一个包含两列的 Oracle 表,recid(帐号)作为主键,xmlrecord 存储所有 xml 数据。我正在尝试使用 SQL 查询为我们的应用程序导出具有多值项的值。排除数据损坏,如果有 c1 m="1" 等,总会有相应的 c2 m="1" 和 c3 m="1" 等等。该表太大而无法多次点击以提取每个项目,因此我需要在一次访问该行时将它们全部从 xmlrecord 中提取出来。我已经尝试过内部连接 ​​(1=1) 和 xmltables,但总是在返回的数据中以 NULLS 结束,或者在新的一行上出现每个新匹配。从顶层提取价值不'

我们的基表数据结构:

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

由于没有多值字段,上述记录可以正常工作。我苦苦挣扎的地方是存储在 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   
4

2 回答 2

2

谢谢大家的评论,但我已经设法通过建立一个适用于这个实例的连接来获得我需要的解决方案。这样做的好处是,无论供应商向我们扔了多少记录,它都会起作用。在某些情况下,“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)
于 2014-01-28T21:34:02.343 回答
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 想出一种方法,如果我想办法,我会更新答案。

于 2014-01-23T15:55:46.863 回答