伙计们,我知道这是一个非常糟糕的主意,这个表需要规范化。但不幸的是我无法改变架构。
我们在Oracle DB中有一个表,如
id|value | other_columns
----------------------------
1|a,b,c |some values
我们可以用
之类的东西创建一个视图id|value
-----------
1|a
1|b
1|c
提前感谢您的帮助。
答案 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机器,但希望能帮到你。