sql >> データベース >  >> RDS >> PostgreSQL

カンマ区切りの値を固定列数のターゲットテーブルに分割します

    通常、CSV値を単一の列に格納することは不適切な設計です。可能であれば、代わりに配列または適切に正規化された設計を使用してください。

    あなたの現在の状況に固執している間...

    既知の少数の要素の最大数の場合

    トリックや再帰のない簡単な解決策で十分です:

    SELECT id, 1 AS rnk
         , split_part(csv, ', ', 1) AS c1
         , split_part(csv, ', ', 2) AS c2
         , split_part(csv, ', ', 3) AS c3
         , split_part(csv, ', ', 4) AS c4
         , split_part(csv, ', ', 5) AS c5
    FROM   tbl
    WHERE  split_part(csv, ', ', 1) <> '' -- skip empty rows
    
    UNION ALL
    SELECT id, 2
         , split_part(csv, ', ', 6)
         , split_part(csv, ', ', 7)
         , split_part(csv, ', ', 8)
         , split_part(csv, ', ', 9)
         , split_part(csv, ', ', 10)
    FROM   tbl
    WHERE  split_part(csv, ', ', 6) <> '' -- skip empty rows
    
    -- three more blocks to cover a maximum "around 20"
    
    ORDER  BY id, rnk;
    

    db <> fiddle こちら

    id 元のテーブルのPKです。
    これは、明らかに「、」を区切り文字として想定しています。
    簡単に適応できます。

    関連:

    要素数が不明な場合

    色々な方法。 1つの方法では、 regexp_replace()を使用します。 ネストを解除する前に、5つおきのセパレータを交換します...

    -- for any number of elements
    SELECT t.id, c.rnk
         , split_part(c.csv5, ', ', 1) AS c1
         , split_part(c.csv5, ', ', 2) AS c2
         , split_part(c.csv5, ', ', 3) AS c3
         , split_part(c.csv5, ', ', 4) AS c4
         , split_part(c.csv5, ', ', 5) AS c5
    FROM   tbl t
         , unnest(string_to_array(regexp_replace(csv, '((?:.*?,){4}.*?),', '\1;', 'g'), '; ')) WITH ORDINALITY c(csv5, rnk)
    ORDER  BY t.id, c.rnk;
    

    db <> fiddle こちら

    これは、選択したセパレータ;を前提としています。 決して 文字列に表示されます。 (,と同じように 表示されることはありません。)

    正規表現パターンが重要です:'((?:.*?,){4}.*?),'

    (?:) ... 「キャプチャしない」括弧のセット
    () ... 括弧のセットを「キャプチャ」する
    *? ... 貪欲でない数量詞
    {4}? ...正確に4つの一致のシーケンス

    置換'\1;' 後方参照 が含まれています \1

    'g' 繰り返し交換するには4番目の関数パラメータが必要です。

    さらに読む:

    これを解決する他の方法には、再帰CTEまたは集合を返す関数が含まれます...

    右から左に記入

    右側から始まる値を列に配置する方法 で追加したように )
    次のような数字をカウントダウンするだけです:

    SELECT t.id, c.rnk
         , split_part(c.csv5, ', ', 5) AS c1
         , split_part(c.csv5, ', ', 4) AS c2
         , split_part(c.csv5, ', ', 3) AS c3
         , split_part(c.csv5, ', ', 2) AS c4
         , split_part(c.csv5, ', ', 1) AS c5
    FROM ...
    

    db <> fiddle こちら



    1. JDBC 4のjava.sql.Clob.free()メソッドと下位互換性

    2. さまざまなレコードで多くの条件を満たす列を選択する

    3. master..spt_valuesを使用して列を分割する理由(および方法)

    4. 10進数のmysqlとストレージスペース?