2016-09-07 4 views
0

COBOL 프로그램에서 작업하는 동안 광산 동료가이 문제를 발견하고 결국 응용 프로그램 수준에서 해결했습니다. SQL을 사용하여 데이터 액세스 수준에서 문제를 해결할 수 있는지 궁금합니다. 이것은 어떻게 든 this other question과 관련이 있지만 ANSI SQL 만 사용하고 싶습니다.CSV 필드를 SQL의 다른 행으로 분할

가변 길이 CSV 행을 포함하는 VARCHAR 필드에서 작동하는 단일 SQL 선택 쿼리를 찾고 있습니다. 쿼리의 목적은 자체 결과 집합 행의 모든 ​​CSV 필드를 분할하는 것입니다. 여기

스키마 및 데이터 예입니다 (여기에 fiddle입니다) :

Hello 
world 
! 
Haloa 
! 
Have 
a 
nice 
day 
! 

CSV : 여기

CREATE TABLE table1 (`field` varchar(100)); 

INSERT INTO table1 (`field`) 
     VALUES 
      ('Hello,world,!') , 
      ('Haloa,!')   , 
      ('Have,a,nice,day,!'); 

내가 쿼리에서이하고자하는 출력 사용되는 구분 기호는 쉼표이며, 지금은 탈출에 대해 걱정하지 않을 것입니다.

당신이 뭔가를 (어쩌면 가장 우아한 아니지만 그것은 당신이 원하는 결과 제공)를 사용할 수 오라클에서
+0

귀하의 DBMS에 따라 다릅니다. 분할 함수의 구현이 있습니다 (많은 언어와 비슷합니다). 구분 기호로', '를 사용하여 각 테이블 레코드 (필드)에 대해 호출해야합니다. DBMS에서 사용할 수 없다면 간단한 배열/커서/결과 집합을 반환하는 간단한 함수를 작성할 수 있습니다. – FDavidov

+0

사용중인 dbms에 태그를 지정하십시오. – jarlh

+1

처음부터 쉼표로 분리 된 값을 SQL 테이블에 저장하지 않으면 많은 두통을 예방할 수 있습니다. 데이타베이스를 제어 할 수있는 것처럼 보입니다. 완전히 피할 수있는 문제에 대한 대안을 만드는 데 시간을 낭비하지 말고 올바르게 설계하십시오. – Tomalak

답변

2

지금까지 내가 말할 수있는 건,이 ANSI의 SQL입니다 :

with recursive word_list (field, word, rest, field_id, level) as (    
    select field, 
     substring(field from 1 for position(',' in field) - 1) as word, 
     substring(field from position(',' in field) + 1) as rest, 
     row_number() over() as field_id, 
     1 
    from table1 
    union all 
    select c.field, 
     case 
      when position(',' in p.rest) = 0 then p.rest 
      else substring(p.rest from 1 for position(',' in p.rest) - 1) 
     end as word, 
     case 
      when position(',' in p.rest) = 0 then null 
      else substring(p.rest from position(',' in p.rest) + 1) 
     end as rest, 
     p.field_id, 
     p.level + 1 
    from table1 as c 
    join word_list p on c.field = p.field and position(',' in p.rest) >= 0 
) 
select word 
from word_list 
order by field_id, level; 
,536가

이 값은 field의 값이 고유하다고 가정합니다. 여기

는 실행 예입니다 http://rextester.com/NARS7464

+0

이것은 놀랍습니다. 다음은 작동 할 수있는 데이터베이스의 개요입니다. https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL#Common_table_expression –

0

- 단순히 your_table_nametab 교체 : 그것은 나에게 결과를 제공

WITH 
tab2 AS (
SELECT t.field, 
     CASE WHEN INSTR(t.field, ',', 1, 1) > 0 AND regexp_count(t.field,',') >= 1 THEN INSTR(t.field, ',', 1, 1) ELSE NULL END AS pos1, 
     CASE WHEN INSTR(t.field, ',', 1, 2) > 0 AND regexp_count(t.field,',') >= 2 THEN INSTR(t.field, ',', 1, 2) ELSE NULL END AS pos2, 
     CASE WHEN INSTR(t.field, ',', 1, 3) > 0 AND regexp_count(t.field,',') >= 3 THEN INSTR(t.field, ',', 1, 3) ELSE NULL END AS pos3, 
     CASE WHEN INSTR(t.field, ',', 1, 4) > 0 AND regexp_count(t.field,',') >= 4 THEN INSTR(t.field, ',', 1, 4) ELSE NULL END AS pos4, 
     CASE WHEN INSTR(t.field, ',', 1, 5) > 0 AND regexp_count(t.field,',') >= 5 THEN INSTR(t.field, ',', 1, 5) ELSE NULL END AS pos5, 
     CASE WHEN INSTR(t.field, ',', 1, 6) > 0 AND regexp_count(t.field,',') >= 6 THEN INSTR(t.field, ',', 1, 6) ELSE NULL END AS pos6 
FROM tab t 
), 
tab3 AS (
SELECT SUBSTR(tt.field,1,tt.pos1-1) AS col1, 
     SUBSTR(tt.field,tt.pos1+1, CASE WHEN tt.pos2 IS NULL THEN LENGTH(tt.field) - tt.pos1 ELSE tt.pos2 - tt.pos1 - 1 END) AS col2, 
     SUBSTR(tt.field,tt.pos2+1, CASE WHEN tt.pos3 IS NULL THEN LENGTH(tt.field) - tt.pos2 ELSE tt.pos3 - tt.pos2 - 1 END) AS col3, 
     SUBSTR(tt.field,tt.pos3+1, CASE WHEN tt.pos4 IS NULL THEN LENGTH(tt.field) - tt.pos3 ELSE tt.pos4 - tt.pos3 - 1 END) AS col4, 
     SUBSTR(tt.field,tt.pos4+1, CASE WHEN tt.pos5 IS NULL THEN LENGTH(tt.field) - tt.pos4 ELSE tt.pos5 - tt.pos4 - 1 END) AS col5, 
     SUBSTR(tt.field,tt.pos5+1, CASE WHEN tt.pos6 IS NULL THEN LENGTH(tt.field) - tt.pos5 ELSE tt.pos6 - tt.pos5 - 1 END) AS col6 
     ,ROWNUM AS r 
FROM tab2 tt 
), 
tab4 AS (
SELECT ttt.col1 AS col FROM tab3 ttt WHERE r = 1 
UNION ALL SELECT ttt.col2 FROM tab3 ttt WHERE r = 1 
UNION ALL SELECT ttt.col3 FROM tab3 ttt WHERE r = 1 
UNION ALL SELECT ttt.col4 FROM tab3 ttt WHERE r = 1 
UNION ALL SELECT ttt.col5 FROM tab3 ttt WHERE r = 1 
UNION ALL SELECT ttt.col6 FROM tab3 ttt WHERE r = 1 
UNION ALL 
SELECT ttt.col1 FROM tab3 ttt WHERE r = 2 
UNION ALL SELECT ttt.col2 FROM tab3 ttt WHERE r = 2 
UNION ALL SELECT ttt.col3 FROM tab3 ttt WHERE r = 2 
UNION ALL SELECT ttt.col4 FROM tab3 ttt WHERE r = 2 
UNION ALL SELECT ttt.col5 FROM tab3 ttt WHERE r = 2 
UNION ALL SELECT ttt.col6 FROM tab3 ttt WHERE r = 2 
UNION ALL 
SELECT ttt.col1 FROM tab3 ttt WHERE r = 3 
UNION ALL SELECT ttt.col2 FROM tab3 ttt WHERE r = 3 
UNION ALL SELECT ttt.col3 FROM tab3 ttt WHERE r = 3 
UNION ALL SELECT ttt.col4 FROM tab3 ttt WHERE r = 3 
UNION ALL SELECT ttt.col5 FROM tab3 ttt WHERE r = 3 
UNION ALL SELECT ttt.col6 FROM tab3 ttt WHERE r = 3 
UNION ALL 
SELECT ttt.col1 FROM tab3 ttt WHERE r = 4 
UNION ALL SELECT ttt.col2 FROM tab3 ttt WHERE r = 4 
UNION ALL SELECT ttt.col3 FROM tab3 ttt WHERE r = 4 
UNION ALL SELECT ttt.col4 FROM tab3 ttt WHERE r = 4 
UNION ALL SELECT ttt.col5 FROM tab3 ttt WHERE r = 4 
UNION ALL SELECT ttt.col6 FROM tab3 ttt WHERE r = 4 
UNION ALL 
SELECT ttt.col1 FROM tab3 ttt WHERE r = 5 
UNION ALL SELECT ttt.col2 FROM tab3 ttt WHERE r = 5 
UNION ALL SELECT ttt.col3 FROM tab3 ttt WHERE r = 5 
UNION ALL SELECT ttt.col4 FROM tab3 ttt WHERE r = 5 
UNION ALL SELECT ttt.col5 FROM tab3 ttt WHERE r = 5 
UNION ALL SELECT ttt.col6 FROM tab3 ttt WHERE r = 5 
) 
SELECT col 
FROM tab4 
WHERE col IS NOT NULL 

을 :

1 Hello 
2 world 
3 ! 
4 Haloa 
5 ! 
6 Have 
7 a 
8 nice 
9 day 
10 ! 
0

FWIW가 여기에 또 다른 오라클 구체적인 방법입니다. 어쩌면 미래의 검색자를 생각 나게 도울 것입니다.

SQL> with tbl(rownbr, col1) as (
      select 1, 'Hello,world,!'  from dual union 
      select 2, 'Haloa,!'   from dual union 
      select 3, 'Have,a,nice,day,!' from dual 
    ) 
    SELECT rownbr, column_value substring_nbr, 
     regexp_substr(col1, '(.*?)(,|$)', 1, column_value, null, 1) 
    FROM tbl, 
       TABLE(
        CAST(
        MULTISET(SELECT LEVEL 
           FROM dual 
           CONNECT BY LEVEL <= REGEXP_COUNT(col1, ',')+1 
          ) AS sys.OdciNumberList 
       ) 
       ) 
     order by rownbr, substring_nbr; 

    ROWNBR SUBSTRING_NBR REGEXP_SUBSTR(COL 
---------- ------------- ----------------- 
     1    1 Hello 
     1    2 world 
     1    3 ! 
     2    1 Haloa 
     2    2 ! 
     3    1 Have 
     3    2 a 
     3    3 nice 
     3    4 day 
     3    5 ! 

10 rows selected. 

SQL> 
관련 문제