2011-06-03 46 views
1

創建一個視圖/臨時表可能重複:
Comma Separated values in Oracle從柱CSV

夥計們,我知道它的exteremly壞主意,這表需要進行標準化。但不幸的是,我無法改變架構。

我們在Oracle數據庫表中,作爲

id|value | other_columns 
---------------------------- 
1|a,b,c |some values 

我們可以創建類似

id|value 
----------- 
1|a 
1|b 
1|c 

預先感謝幫助的東西視圖。

+0

什麼版本的Oracle? 11g介紹了PIVOT,但將您的價值觀列入單一專欄中,我不確定這會讓您一路走到您想去的地方。 – 2011-06-03 15:18:31

+1

不是一個笨蛋,那個問題想要一個過程來拆分列值。這篇文章想看看。 – DCookie 2011-06-03 16:11:26

+0

你說你不能改變模式,是否包括添加一個表和觸發器來保持它與oprginal表同步?每次更新字段時,每次需要查看數據時,分割效果會更好。 – HLGEM 2011-06-03 19:15:10

回答

1

我不認爲這是在密切投票中引用的問題的確切副本。類似的是,但不一樣。

不完全是美麗的,但:

CREATE OR REPLACE VIEW your_view AS 
SELECT tt.ID, SUBSTR(value, sp, ep-sp) split, other_col1, other_col2... 
    FROM (SELECT id, value 
      , INSTR(','||value, ',', 1, L) sp -- 1st posn of substr at this level 
      , INSTR(value||',', ',', 1, L) ep -- posn of delimiter at this level 
      FROM tt JOIN (SELECT LEVEL L FROM dual CONNECT BY LEVEL < 20) q -- 20 is max #substrings 
        ON LENGTH(value)-LENGTH(REPLACE(value,','))+1 >= L 
) qq JOIN tt on qq.id = tt.id; 

,其中TT是你的表。

適用於長度超過1或null的csv值。 CONNECT BY LEVEL20是任意的,根據您的情況進行調整。

舉例說明:

SQL> CREATE TABLE tt (ID INTEGER, c VARCHAR2(20), othercol VARCHAR2(20)); 

    Table created 
    SQL> INSERT INTO tt VALUES (1, 'a,b,c', 'val1'); 

    1 row inserted 
    SQL> INSERT INTO tt VALUES (2, 'd,e,f,g', 'val2'); 

    1 row inserted 
    SQL> INSERT INTO tt VALUES (3, 'a,f', 'val3'); 

    1 row inserted 
    SQL> INSERT INTO tt VALUES (4,'aa,bbb,cccc', 'val4'); 

    1 row inserted 
    SQL> CREATE OR REPLACE VIEW myview AS 
     2 SELECT tt.ID, SUBSTR(c, sp, ep-sp+1) splitval, othercol 
     3 FROM (SELECT ID 
     4    , INSTR(','||c,',',1,L) sp, INSTR(c||',',',',1,L)-1 ep 
     5   FROM tt JOIN (SELECT LEVEL L FROM dual CONNECT BY LEVEL < 20) q 
     6      ON LENGTH(c)-LENGTH(REPLACE(c,','))+1 >= L 
     7 ) q JOIN tt ON q.id =tt.id; 

    View created 
    SQL> select * from myview order by 1,2; 

            ID SPLITVAL    OTHERCOL 
--------------------------------------- -------------------- -------------------- 
             1 a     val1 
             1 b     val1 
             1 c     val1 
             2 d     val2 
             2 e     val2 
             2 f     val2 
             2 g     val2 
             3 a     val3 
             3 f     val3 
             4 aa     val4 
             4 bbb     val4 
             4 cccc     val4 

12 rows selected 

SQL> 
+0

這工作,非常感謝! – Saurabh 2011-06-09 12:18:40

1

我的確在過去類似的東西了這一點。您需要創建一個接受輸入字符串和分隔符並返回數據集的函數。如果分隔符被忽略,則假定逗號。

首先創建一個新的類型,代表字符串表:

create or replace type varcharTableType as table of varchar2(255); 
/

然後建立這個功能:

create or replace function splitString(
    allValues in varchar2, 
    delim in varchar2 default ',' 
) 
return varcharTableType 
as 
    str  varchar2(255) := allValues || delim; 
    pos  number; 
    dataset varcharTableType := varcharTableType(); 
begin 
    loop 
    pos := instr(str, delim); 
    exit when (nvl(pos, 0) = 0); 
    dataset.extend; 
    dataset(dataset.count) := ltrim(rtrim(substr(str, 1, pos - 1))); 
    str := substr(str, pos + length(delim)); 
    end loop; 
    return dataset; 
end; 
/

最後,調用爲:

select * 
    from table(cast(splitString('a,b,c') as varcharTableType)); 

COLUMN_VALUE                                                              
--------------- 
a                                                                
b                                                               
c                                                               

3 rows selected 

要回答你的特定的情況下,您只需創建一個視圖,將您的表與該函數表連接起來,如下所示:

create or replace view splitView as 
    select yourTable.id, s.column_value as value 
     from yourTable, 
      table(cast(splitString(yourTable.value) as varcharTableType)) s; 


    select * from splitView; 

    id value                                                              
    ---- --------------- 
    1 a                                                                
    1 b                                                               
    1 c                                                               

    3 rows selected 

我不確定最後一個查詢是否可以正常工作,因爲我現在沒有Oracle機器,但希望能幫助您。