通常、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番目の関数パラメータが必要です。
さらに読む:
- PostgreSQLとregexp_split_to_array+unnest
- 適用`テキスト配列のtrim()`と`regexp_replace() `
- 要素番号付きのPostgreSQLunnest()
これを解決する他の方法には、再帰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 こちら