使用CSV从列创建视图/临时表

时间:2011-06-03 13:49:19

标签: sql oracle csv

  

可能重复:
  Comma Separated values in Oracle

伙计们,我知道这是一个非常糟糕的主意,这个表需要规范化。但不幸的是我无法改变架构。

我们在Oracle DB中有一个表,如

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

我们可以用

之类的东西创建一个视图
id|value   
-----------
 1|a
 1|b
 1|c

提前感谢您的帮助。

2 个答案:

答案 0 :(得分: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的csv值或null。 CONNECT BY LEVEL&lt; 20是任意的,根据你的情况调整。

举例说明:

    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> 

答案 1 :(得分: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机器,但希望能帮到你。