次のような表があります。
-------------
ID | NAME
-------------
1001 | A,B,C
1002 | D,E,F
1003 | C,E,G
-------------
これらの値を次のように表示する必要があります。
-------------
ID | NAME
-------------
1001 | A
1001 | B
1001 | C
1002 | D
1002 | E
1002 | F
1003 | C
1003 | E
1003 | G
-------------
私はやってみました:
select split('A,B,C,D,E,F', ',') from dual; -- WILL RETURN COLLECTION
select column_value
from table (select split('A,B,C,D,E,F', ',') from dual); -- RETURN COLUMN_VALUE
以下のクエリを使用してみてください:
WITH T AS (SELECT 'A,B,C,D,E,F' STR FROM DUAL) SELECT
REGEXP_SUBSTR (STR, '[^,]+', 1, LEVEL) SPLIT_VALUES FROM T
CONNECT BY LEVEL <= (SELECT LENGTH (REPLACE (STR, ',', NULL)) FROM T)
IDを含むクエリの下:
WITH TAB AS
(SELECT '1001' ID, 'A,B,C,D,E,F' STR FROM DUAL
)
SELECT ID,
REGEXP_SUBSTR (STR, '[^,]+', 1, LEVEL) SPLIT_VALUES FROM TAB
CONNECT BY LEVEL <= (SELECT LENGTH (REPLACE (STR, ',', NULL)) FROM TAB);
編集:複数のIDと複数の区切りに対して以下のクエリを使用してみてください:
WITH TAB AS
(SELECT '1001' ID, 'A,B,C,D,E,F' STR FROM DUAL
UNION
SELECT '1002' ID, 'D,E,F' STR FROM DUAL
UNION
SELECT '1003' ID, 'C,E,G' STR FROM DUAL
)
select id, substr(STR, instr(STR, ',', 1, lvl) + 1, instr(STR, ',', 1, lvl + 1) - instr(STR, ',', 1, lvl) - 1) name
from
( select ',' || STR || ',' as STR, id from TAB ),
( select level as lvl from dual connect by level <= 100 )
where lvl <= length(STR) - length(replace(STR, ',')) - 1
order by ID, NAME
複数のオプションがあります。 Oracle のテーブル内の分割されたコンマ区切り文字列を参照してください。
REGEXP_SUBSTRを使用:
SQL> WITH sample_data AS(
2 SELECT 10001 ID, 'A,B,C' str FROM dual UNION ALL
3 SELECT 10002 ID, 'D,E,F' str FROM dual UNION ALL
4 SELECT 10003 ID, 'C,E,G' str FROM dual
5 )
6 -- end of sample_data mimicking real table
7 SELECT distinct id, trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str
8 FROM sample_data
9 CONNECT BY LEVEL <= regexp_count(str, ',')+1
10 ORDER BY ID
11 /
ID STR
---------- -----
10001 A
10001 B
10001 C
10002 D
10002 E
10002 F
10003 C
10003 E
10003 G
9 rows selected.
SQL>
XMLTABLEを使用:
SQL> WITH sample_data AS(
2 SELECT 10001 ID, 'A,B,C' str FROM dual UNION ALL
3 SELECT 10002 ID, 'D,E,F' str FROM dual UNION ALL
4 SELECT 10003 ID, 'C,E,G' str FROM dual
5 )
6 -- end of sample_data mimicking real table
7 SELECT id,
8 trim(COLUMN_VALUE) str
9 FROM sample_data,
10 xmltable(('"'
11 || REPLACE(str, ',', '","')
12 || '"'))
13 /
ID STR
---------- ---
10001 A
10001 B
10001 C
10002 D
10002 E
10002 F
10003 C
10003 E
10003 G
9 rows selected.
Lalit Kumar Bの解決策を試してみましたが、今のところうまくいきました。しかし、より多くのデータを使用すると、パフォーマンスの問題(> 60行、> 7レベル)に遭遇しました。そのため、より静的なバリエーションを使用しました。代わりに共有したいと思います。
WITH T AS (
SELECT 1001 AS ID, 'A,B,C' AS NAME FROM DUAL
UNION SELECT 1002 AS ID, 'D,E,F' AS NAME FROM DUAL
UNION SELECT 1003 AS ID, 'C,E,G' AS NAME FROM DUAL
) --SELECT * FROM T
SELECT ID as ID,
distinct_column AS NAME
FROM ( SELECT t.ID,
trim(regexp_substr(t.NAME, '[^,]+', 1,1)) AS c1,
trim(regexp_substr(t.NAME, '[^,]+', 1,2)) AS c2,
trim(regexp_substr(t.NAME, '[^,]+', 1,3)) AS c3,
trim(regexp_substr(t.NAME, '[^,]+', 1,4)) AS c4 -- etc.
FROM T )
UNPIVOT ( distinct_column FOR cn IN ( c1, c2, c3, c4 ) )
ID NAME
------ ------
1001 A
1001 B
1001 C
1002 D
1002 E
1002 F
1003 C
1003 E
1003 G
9 Zeilen gewählt
この方法で同様の問題を解決しました...
select YT.ID,
REPLACE(REGEXP_SUBSTR(','||YT.STR||',',',.*?,',1,lvl.lvl),',','') AS STR
from YOURTABLE YT
join (select level as lvl
from dual
connect by level <= (select max(regexp_count(STR,',')+1) from YOURTABLE)
) lvl on lvl.lvl <= regexp_count(YT.STR,',')+1
CONNECT BYまたはREGEXPを使用しないでください。複雑なクエリでデカルト積が生成されます。さらに、上記のソリューションでは、組み合わせのリストではなく、可能な結果(A、B、C、D、E、F)を知っていることを期待しています。
XMLTableを使用:
SELECT c.fname, c.lname,
trim(COLUMN_VALUE) EMAIL_ADDRESS
FROM
CONTACTS c, CONTACT_STATUS s,
xmltable(('"'
|| REPLACE(EMAIL_ADDRESS, ';', '","')
|| '"'))
where c.status = s.id
COLUMN_VALUEは、xmltableに属する疑似列です。これは迅速かつ正確で、値を知らなくても列を参照できます。
これにより、列が取得され、値のテーブル「item」、「item2」、「item3」が作成され、ソーステーブル(CONTACTS)に自動的に結合されます。これは数千行でテストされました
注 ';' xmltableの列フィールドの区切り文字です。
次のようなものを試すことができます:
CREATE OR REPLACE TYPE "STR_TABLE"
as table of varchar2
create or replace function GetCollection( iStr varchar2, iSplit char default ',' ) return STR_TABLE as
pStr varchar2(4000) := trim(iStr);
rpart varchar(255);
pColl STR_TABLE := STR_TABLE();
begin
while nvl(length(pStr),0) > 0 loop
pos := inStr(pStr, iSplit );
if pos > 0 then
rpart := substr(pStr,1, pos-1);
pStr := substr(pStr,pos+1,length(pStr));
else
rpart := pStr;
pStr := null;
end if;
if rpart is not null then
pColl.Extend;
pColl(pColl.Count) := rpart;
end if;
end loop;
return pColl;
end;
このバージョンは、1文字より長い文字列でも機能します。
select regexp_substr('A,B,C,Karl-Heinz,D','[^,]+', 1, level) from dual
connect by regexp_substr('A,B,C,Karl-Heinz,D', '[^,]+', 1, level) is not null;
コンマ区切りの文字列を分割し、selectステートメントのIN句に渡す方法 を参照してください