2014-01-19 42 views
4

我花了幾天的時間尋找簡單的解決方案來解決以下問題,我需要一些幫助。我有一個有兩列的Oracle表,recid(Account Number)作爲主鍵,xmlrecord存儲所有的xml數據。我試圖使用SQL查詢爲我們的應用程序導出我們有多值項目的值。排除數據損壞時,如果存在c1 m =「1」等,則始終存在相應的c2 m =「1」和c3 m =「1」。該表太大而無法多次提取每個項目,因此我需要在行的一次訪問中將它們全部從xmlrecord中提取出來。我嘗試了內部連接(1 = 1)和xmltables,但總是以返回的數據或新行中的每個新匹配結束NULLS。來自多個元素的Oracle SQL extractvalue

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

上面記錄將作爲工作有罰款:從頂層提取值不爲我在這種情況下,由於XML的結構

我們的基表的數據結構工作沒有多個有價值的領域。當我掙扎是當存儲在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

問題是,您的XML結構是borked。在同一個環境中名稱完全相同的兩個不同元素不可避免地會導致問題。 – APC

回答

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) 
+0

XMLTABLE救援!我可惜有一天來維護這個數據庫的人:-)。但有時管理層會聽到「XML」,並認爲「噢,我們應該使用它!」 –

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 

您可以繼續爲具有多個屬性,可能的行數工會。

我不認爲這將是一個完整的掃描表很容易做到的,因爲您試圖爲您選擇的每個單獨的行生成多行。

這是一個很好的例子,說明爲什麼在關係數據庫中存儲XML是一個非常糟糕的主意。

我試圖想出一種方法來做到這一點與XMLTABLE,我會更新答案,如果我想辦法。