2016-09-07 7 views
0

COBOLプログラムで作業中に同僚の鉱山でこの問題が発生し、最終的にアプリケーションレベルで解決しました。 SQLを使用してデータアクセスレベルでそれを解決することができるのであれば、私は不思議です。 これは何とかthis other questionに関連していますが、ANSI SQLだけを使用したいと思います。CSVフィールドをSQLの異なる行に分割

可変長のCSV行を含むVARCHARフィールドに作用する1つのSQL選択クエリを探しています。クエリの目的は、独自の結果セット行のすべてのCSVフィールドを分割することです。ここで

は、スキーマとデータとの一例である(ここfiddleです):ここでは

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

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

は、私は、クエリから持っているしたいのですが出力されます:

Hello 
world 
! 
Haloa 
! 
Have 
a 
nice 
day 
! 

CSV使用されている区切り記号はカンマです。今のところ私はエスケープについて心配しません。

あなたがそのような何か(多分それは最もエレガントではないのですが、それはあなたが望む結果を与える)を使用することができオラクルで
+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; 

これは、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は、ここに別のOracleの具体的な方法です。たぶんそれはアイデアを与えたり、少なくとも将来の検索人を助けるでしょう。

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> 
関連する問題