Việc lưu trữ các giá trị CSV trong một cột thường là một thiết kế tồi. Nếu có thể, hãy sử dụng một mảng hoặc một thiết kế chuẩn hóa thích hợp để thay thế.
Trong khi mắc kẹt với tình hình hiện tại của bạn ...
Đối với số phần tử tối đa nhỏ đã biết
Một giải pháp đơn giản không cần thủ thuật hoặc đệ quy sẽ thực hiện được:
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 tại đây
id
là PK của bảng gốc.
Điều này giả định rõ ràng là ',' là dấu phân cách.
Bạn có thể điều chỉnh dễ dàng.
Có liên quan:
Đối với số phần tử không xác định
Nhiều cách khác nhau. Một cách sử dụng regexp_replace()
để thay thế mọi dấu phân cách thứ năm trước khi bỏ ghi chú ...
-- 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 tại đây
Điều này giả định rằng dấu phân tách đã chọn ;
không bao giờ xuất hiện trong chuỗi của bạn. (Cũng giống như ,
không bao giờ có thể xuất hiện.)
Mẫu biểu thức chính quy là khóa:'((?:.*?,){4}.*?),'
(?:)
... tập hợp dấu ngoặc đơn “không ghi lại”
()
... “thu thập” tập hợp các dấu ngoặc đơn
*?
... công cụ định lượng không tham lam
{4}?
... chuỗi đúng 4 trận
Thay thế '\1;'
chứa tham chiếu ngược
\1
.
'g'
vì tham số chức năng thứ tư là bắt buộc để thay thế nhiều lần.
Đọc thêm:
- PostgreSQL ®exp_split_to_array + unnest
- Áp dụng ` trim () `và` regexp_replace () `trên mảng văn bản
- PostgreSQL unnest () với số phần tử
Các cách khác để giải quyết vấn đề này bao gồm CTE đệ quy hoặc hàm trả về tập hợp ...
Điền từ phải sang trái
(Giống như bạn đã thêm trong Làm cách nào để đặt các giá trị bắt đầu từ phía bên phải vào cột?
)
Đơn giản chỉ cần đếm ngược các số như:
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 tại đây