123

これはPHPとMYSQLである程度答えられていることは知っていますが、Oracle 10g(できれば)と11gで文字列(カンマ区切り)を複数の行に分割する最も簡単な方法を教えてもらえないかと思っていました.

表は次のとおりです。

Name | Project | Error 
108    test      Err1, Err2, Err3
109    test2     Err1

私は次のものを作成したい:

Name | Project | Error
108    Test      Err1
108    Test      Err2 
108    Test      Err3 
109    Test2     Err1

スタックに関するいくつかの潜在的な解決策を見てきましたが、それらは単一の列 (カンマ区切りの文字列) のみを占めていました。どんな助けでも大歓迎です。

4

14 に答える 14

142

これは改善された方法かもしれません (regexp と connect by も使用):

with temp as
(
    select 108 Name, 'test' Project, 'Err1, Err2, Err3' Error  from dual
    union all
    select 109, 'test2', 'Err1' from dual
)
select distinct
  t.name, t.project,
  trim(regexp_substr(t.error, '[^,]+', 1, levels.column_value))  as error
from 
  temp t,
  table(cast(multiset(select level from dual connect by  level <= length (regexp_replace(t.error, '[^,]+'))  + 1) as sys.OdciNumberList)) levels
order by name

EDIT : ここでは、クエリの簡単な (「詳細ではない」) 説明を示します。

  1. length (regexp_replace(t.error, '[^,]+')) + 1regexp_replace区切り文字 (この場合はコンマ) 以外のものを消去し、要素length +1(エラー) の数を取得するために使用します。
  2. 階層クエリselect level from dual connect by level <= (...)を使用して、1 からエラーの合計数まで、見つかった一致数が増加する列を作成します。

    プレビュー:

    select level, length (regexp_replace('Err1, Err2, Err3', '[^,]+'))  + 1 as max 
    from dual connect by level <= length (regexp_replace('Err1, Err2, Err3', '[^,]+'))  + 1
    
  3. table(cast(multiset(.....) as sys.OdciNumberList))oracle 型のいくつかのキャストを行います。
    • は、cast(multiset(.....)) as sys.OdciNumberList複数のコレクション (元のデータ セットの行ごとに 1 つのコレクション) を単一の数値コレクション OdciNumberList に変換します。
    • このtable()関数は、コレクションを結果セットに変換します。
  4. FROM結合しないと、データセットとマルチセットの間に相互結合が作成されます。その結果、4 つの一致があるデータ セットの行は 4 回繰り返されます ("column_value" という名前の列の数が増加します)。

    プレビュー:

    select * from 
    temp t,
    table(cast(multiset(select level from dual connect by  level <= length (regexp_replace(t.error, '[^,]+'))  + 1) as sys.OdciNumberList)) levels
    
  5. trim(regexp_substr(t.error, '[^,]+', 1, levels.column_value))は、column_valuenth_appearance/ocurrenceパラメータとして を使用しますregexp_substr
  6. 簡単に視覚化するために、データセットから他の列を追加できます (t.name, t.project例として)。

Oracle ドキュメントへの参照:

于 2014-11-25T22:05:43.773 に答える
32

正規表現は素晴らしいものです:)

with temp as  (
       select 108 Name, 'test' Project, 'Err1, Err2, Err3' Error  from dual
       union all
       select 109, 'test2', 'Err1' from dual
     )

SELECT distinct Name, Project, trim(regexp_substr(str, '[^,]+', 1, level)) str
  FROM (SELECT Name, Project, Error str FROM temp) t
CONNECT BY instr(str, ',', 1, level - 1) > 0
order by Name
于 2013-01-15T04:12:10.063 に答える
31

以下の2つには大きな違いがあります。

  • 単一の区切り文字列の分割
  • テーブル内の複数の行の区切り文字列を分割します。

行を制限しないと、CONNECT BY句によって複数の行が生成され、目的の出力が得られません。

正規表現とは別に、他のいくつかの代替手段が使用されています:

  • XML テーブル
  • モデル

設定

SQL> CREATE TABLE t (
  2    ID          NUMBER GENERATED ALWAYS AS IDENTITY,
  3    text        VARCHAR2(100)
  4  );

Table created.

SQL>
SQL> INSERT INTO t (text) VALUES ('word1, word2, word3');

1 row created.

SQL> INSERT INTO t (text) VALUES ('word4, word5, word6');

1 row created.

SQL> INSERT INTO t (text) VALUES ('word7, word8, word9');

1 row created.

SQL> COMMIT;

Commit complete.

SQL>
SQL> SELECT * FROM t;

        ID TEXT
---------- ----------------------------------------------
         1 word1, word2, word3
         2 word4, word5, word6
         3 word7, word8, word9

SQL>

XMLTABLE の使用:

SQL> SELECT id,
  2         trim(COLUMN_VALUE) text
  3  FROM t,
  4    xmltable(('"'
  5    || REPLACE(text, ',', '","')
  6    || '"'))
  7  /

        ID TEXT
---------- ------------------------
         1 word1
         1 word2
         1 word3
         2 word4
         2 word5
         2 word6
         3 word7
         3 word8
         3 word9

9 rows selected.

SQL>

MODEL句の使用:

SQL> WITH
  2  model_param AS
  3     (
  4            SELECT id,
  5                      text AS orig_str ,
  6                   ','
  7                          || text
  8                          || ','                                 AS mod_str ,
  9                   1                                             AS start_pos ,
 10                   Length(text)                                   AS end_pos ,
 11                   (Length(text) - Length(Replace(text, ','))) + 1 AS element_count ,
 12                   0                                             AS element_no ,
 13                   ROWNUM                                        AS rn
 14            FROM   t )
 15     SELECT   id,
 16              trim(Substr(mod_str, start_pos, end_pos-start_pos)) text
 17     FROM     (
 18                     SELECT *
 19                     FROM   model_param MODEL PARTITION BY (id, rn, orig_str, mod_str)
 20                     DIMENSION BY (element_no)
 21                     MEASURES (start_pos, end_pos, element_count)
 22                     RULES ITERATE (2000)
 23                     UNTIL (ITERATION_NUMBER+1 = element_count[0])
 24                     ( start_pos[ITERATION_NUMBER+1] = instr(cv(mod_str), ',', 1, cv(element_no)) + 1,
 25                     end_pos[iteration_number+1] = instr(cv(mod_str), ',', 1, cv(element_no) + 1) )
 26                 )
 27     WHERE    element_no != 0
 28     ORDER BY mod_str ,
 29           element_no
 30  /

        ID TEXT
---------- --------------------------------------------------
         1 word1
         1 word2
         1 word3
         2 word4
         2 word5
         2 word6
         3 word7
         3 word8
         3 word9

9 rows selected.

SQL>
于 2015-05-05T05:24:26.160 に答える
9

同じ例をさらにいくつか示します。

SELECT trim(regexp_substr('Err1, Err2, Err3', '[^,]+', 1, LEVEL)) str_2_tab
  FROM dual
CONNECT BY LEVEL <= regexp_count('Err1, Err2, Err3', ',')+1
/

SELECT trim(regexp_substr('Err1, Err2, Err3', '[^,]+', 1, LEVEL)) str_2_tab
  FROM dual
CONNECT BY LEVEL <= length('Err1, Err2, Err3') - length(REPLACE('Err1, Err2, Err3', ',', ''))+1
/

また、DBMS_UTILITY.comma_to_table と table_to_comma を使用することもできます: http://www.oracle-base.com/articles/9i/useful-procedures-and-functions-9i.php#DBMS_UTILITY.comma_to_table

于 2013-01-17T20:27:58.823 に答える
4

異なるデータ型へのキャストを可能にする XMLTABLE を使用した代替実装を次に示します。

select 
  xmltab.txt
from xmltable(
  'for $text in tokenize("a,b,c", ",") return $text'
  columns 
    txt varchar2(4000) path '.'
) xmltab
;

... または、区切り文字列がテーブルの 1 つ以上の行に格納されている場合:

select 
  xmltab.txt
from (
  select 'a;b;c' inpt from dual union all
  select 'd;e;f' from dual
) base
inner join xmltable(
  'for $text in tokenize($input, ";") return $text'
  passing base.inpt as "input"
  columns 
    txt varchar2(4000) path '.'
) xmltab
  on 1=1
;
于 2017-12-01T13:16:49.763 に答える
2

connect byまたはregexpを使用しない場合:

    with mytable as (
      select 108 name, 'test' project, 'Err1,Err2,Err3' error from dual
      union all
      select 109, 'test2', 'Err1' from dual
    )
    ,x as (
      select name
      ,project
      ,','||error||',' error
      from mytable
    )
    ,iter as (SELECT rownum AS pos
        FROM all_objects
    )
    select x.name,x.project
    ,SUBSTR(x.error
      ,INSTR(x.error, ',', 1, iter.pos) + 1
      ,INSTR(x.error, ',', 1, iter.pos + 1)-INSTR(x.error, ',', 1, iter.pos)-1
    ) error
    from x, iter
    where iter.pos < = (LENGTH(x.error) - LENGTH(REPLACE(x.error, ','))) - 1;
于 2015-11-26T21:31:47.747 に答える
0

Oracle APEX 5.1以降がインストールされている場合は、次のような便利APEX_STRING.splitな機能を使用できます:

select q.Name, q.Project, s.column_value as Error
from mytable q,
     APEX_STRING.split(q.Error, ',') s

2 番目のパラメーターは区切り文字列です。また、実行する分割数を制限する 3 番目のパラメーターも受け入れます。

https://docs.oracle.com/en/database/oracle/application-express/20.1/aeapi/SPLIT-Function-Signature-1.html#GUID-3BE7FF37-E54F-4503-91B8-94F374E243E6

于 2020-10-06T04:36:55.580 に答える
-1

私は DBMS_UTILITY.comma_to _table 関数を実際に使用して、次のようにコードを動作させました

declare
l_tablen  BINARY_INTEGER;
l_tab     DBMS_UTILITY.uncl_array;
cursor cur is select * from qwer;
rec cur%rowtype;
begin
open cur;
loop
fetch cur into rec;
exit when cur%notfound;
DBMS_UTILITY.comma_to_table (
     list   => rec.val,
     tablen => l_tablen,
     tab    => l_tab);
FOR i IN 1 .. l_tablen LOOP
    DBMS_OUTPUT.put_line(i || ' : ' || l_tab(i));
END LOOP;
end loop;
close cur;
end; 

私は自分のテーブルと列の名前を使用していました

于 2014-10-20T12:18:46.643 に答える