web-dev-qa-db-ja.com

カンマ区切りのエントリを行に分割する

私はこのようなテーブルを持っています:

|   ID   |  OtherID  | Data
+--------+-----------+---------------------------
|  5059  |   73831   | 5103,5107
|  5059  |   73941   | 5103,5104,5107
|  5059  |   73974   | 5103,5106,5107,5108

そして結果は次のように個々の行を返すはずです:

|   ID   |  OtherID  | Data
+--------+-----------+--------------------------
|  5059  |   73831   | 5103
|  5059  |   73831   | 5107
|  5059  |   73941   | 5103
|  5059  |   73941   | 5104
|  5059  |   73941   | 5107
|  5059  |   73974   | 5103
|  5059  |   73974   | 5106
|  5059  |   73974   | 5107
|  5059  |   73974   | 5108

基本的に、データをコンマで個々の行に分割しますか?

結果は一時テーブルに格納されます(いいね:ID, OtherID, NewID)。

私のバージョンDB2は9.7です

4
Yuri Marques

私が行っているいくつかの作業と Serge RielauとRick SwagermanによるIBMのdeveloperWorks に投稿されたソリューションへのいくつかの変更に基づいて、データセットのソリューションを思いつきました。

データセットアップクエリ:

DECLARE GLOBAL TEMPORARY TABLE sample_data (id INTEGER, otherid integer, data VARCHAR(255)) WITH REPLACE ON COMMIT preserve rows NOT logged;
INSERT INTO session.sample_data SELECT 5059, 73831, '5103,5107' FROM sysibm.sysdummy1;
INSERT INTO session.sample_data SELECT 5059, 73941, '5103,5104,5107' FROM sysibm.sysdummy1;
INSERT INTO session.sample_data SELECT 5059, 73974, '5103,5106,5107,5108' FROM sysibm.sysdummy1;

ソリューション選択クエリ:

WITH
split_data AS
(
    SELECT
        id as group_by_1,
        otherid as group_by_2,
        data AS split_string,
        ','  AS split
    FROM
        session.sample_data
)
,
rec
(
    group_by_1,
    group_by_2,
    split_string,
    split,
    row_num,
    column_value,
    pos
) AS
(
    SELECT
        group_by_1,
        group_by_2,
        split_string,
        split,
        1,
        VARCHAR(SUBSTR(split_string, 1, DECODE(INSTR(split_string, split, 1), 0, LENGTH(split_string), INSTR(split_string, split, 1) - 1)), 255),
        INSTR(split_string, split, 1) + LENGTH(split)
    FROM
        split_data
    UNION ALL
    SELECT
        group_by_1,
        group_by_2,
        split_string,
        split,
        row_num + 1,
        VARCHAR(SUBSTR(split_string, pos, DECODE(INSTR(split_string, split, pos), 0, LENGTH(split_string) - pos + 1, INSTR(split_string, split, pos) - pos)), 255),
        INSTR(split_string, split, pos) + LENGTH(split)
    FROM
        rec
    WHERE
        row_num < 30000
    AND pos > LENGTH(split)
)
SELECT
    group_by_1 as id,
    group_by_2 as otherid,
    column_value AS data
FROM
    rec
ORDER BY
    group_by_1,
    group_by_2,
    row_num;

結果:

ID  OTHERID DATA
5059    73831   5103
5059    73831   5107
5059    73941   5103
5059    73941   5104
5059    73941   5107
5059    73974   5103
5059    73974   5106
5059    73974   5107
5059    73974   5108

コメント:

ソリューション選択クエリは、RECテーブル定義に同じ数のGROUP_BY_X行(Oから複数)を含め、2つの結合された副選択の行を一致させることにより、特定の結果のニーズに合わせて変更できます。

2
Jeff Rudnick

パーティーには少し遅れましたが、最近のプロジェクトで、より単純なソリューションで同様のことを達成する必要があり、再帰的なSQLではなくXMLTABLEを使用してこのアプローチを共有する必要があると考えました。

データ設定

データのセットアップは、Jeff Rudnickの回答と同じです。

DECLARE GLOBAL TEMPORARY TABLE session.sample_data (
    ID        INTEGER,
    OtherId   INTEGER,
    Data      VARCHAR(255)
    )
    WITH REPLACE ON COMMIT PRESERVE ROWS NOT LOGGED;
INSERT INTO session.sample_data values
    (5059, 73831, '5103,5107'),
    (5059, 73941, '5103,5104,5107'),
    (5059, 73974, '5103,5106,5107,5108');

解決

SELECT sd.ID, sd.OtherId, si.item as NewId
  from session.sample_data sd
      ,XMLTABLE('$doc/items/item'
          PASSING XMLPARSE(DOCUMENT CAST('<items><item><value>'||replace(sd.Data,',','</value></item><item><value>')||'</value></item></items>' as CLOB)) as "doc"
          COLUMNS
          ITEM VARCHAR(255) PATH 'value'
      ) si
;

結果

ID     OTHERID   NEWID
5059   73831     5103
5059   73831     5107
5059   73941     5103
5059   73941     5104
5059   73941     5107
5059   73974     5103
5059   73974     5106
5059   73974     5107
5059   73974     5108
0
gwc

値タグを取り除くことで、XMLTABLE()を介して最後のソリューションを短縮することもできます。

SELECT sd.ID, sd.OtherId, si.item as NewId
  from session.sample_data sd
      ,XMLTABLE('$doc/items/item'
          PASSING XMLPARSE(DOCUMENT CAST(   '<items><item>'
                                         || replace(sd.Data , ',' , '</item><item>')
                                         || '</item></items>' as CLOB
                                        )
                           ) as "doc"
          COLUMNS
          ITEM VARCHAR(255) PATH '.'
      ) si ;
0
Walter Huth