2011-12-21 28 views
38

Tôi có dấu phẩy tách dữ liệu trong một cột:Chia dấu phẩy tách dữ liệu cột vào cột bổ sung

Column 
------- 
a,b,c,d 

Tôi muốn chia dấu phẩy tách dữ liệu thành nhiều cột để có được kết quả này:

Column1 Column2 Column3 Column4 
------- ------- ------- ------- 
a  b  c  d 

Làm thế nào điều này có thể đạt được?

Trả lời

45

Nếu số lĩnh vực trong CSV là hằng số thì bạn có thể làm điều gì đó như thế này:

select a[1], a[2], a[3], a[4] 
from (
    select regexp_split_to_array('a,b,c,d', ',') 
) as dt(a) 

Ví dụ:

=> select a[1], a[2], a[3], a[4] from (select regexp_split_to_array('a,b,c,d', ',')) as dt(a); 
a | a | a | a 
---+---+---+--- 
a | b | c | d 
(1 row) 

Nếu số lĩnh vực trong CSV phải là không đổi sau đó bạn có thể nhận được số lượng trường tối đa bằng một cái gì đó như thế này:

select max(array_length(regexp_split_to_array(csv, ','), 1)) 
from your_table 

và sau đó b liệt kê danh sách cột a[1], a[2], ..., a[M] thích hợp cho truy vấn của bạn. Vì vậy, nếu ở trên cung cấp cho bạn tối đa 6, bạn sẽ sử dụng điều này:

select a[1], a[2], a[3], a[4], a[5], a[6] 
from (
    select regexp_split_to_array(csv, ',') 
    from your_table 
) as dt(a) 

Bạn có thể kết hợp hai truy vấn đó thành hàm nếu bạn muốn.

Ví dụ: đặt dữ liệu này (đó là một NULL ở hàng cuối cùng):

=> select * from csvs; 
    csv  
------------- 
1,2,3 
1,2,3,4 
1,2,3,4,5,6 

(4 rows) 

=> select max(array_length(regexp_split_to_array(csv, ','), 1)) from csvs; 
max 
----- 
    6 
(1 row) 

=> select a[1], a[2], a[3], a[4], a[5], a[6] from (select regexp_split_to_array(csv, ',') from csvs) as dt(a); 
a | a | a | a | a | a 
---+---+---+---+---+--- 
1 | 2 | 3 | | | 
1 | 2 | 3 | 4 | | 
1 | 2 | 3 | 4 | 5 | 6 
    | | | | | 
(4 rows) 

Kể từ delimiter của bạn là một chuỗi cố định đơn giản, bạn cũng có thể sử dụng string_to_array thay vì regexp_split_to_array:

select ... 
from (
    select string_to_array(csv, ',') 
    from csvs 
) as dt(a); 

Nhờ Michael cho lời nhắc về chức năng này.

Bạn thực sự nên thiết kế lại lược đồ cơ sở dữ liệu của mình để tránh cột CSV nếu có thể. Bạn nên sử dụng một cột mảng hoặc một bảng riêng biệt để thay thế.

+0

Cảm ơn bạn sẽ kiểm tra và hoàn nguyên – Gallop

+6

Xem xét sử dụng 'string_to_array' thay vì' regexp_split_to_array'; nó sẽ nhanh hơn vì nó không có chi phí xử lý biểu thức chính quy. – Michael

+1

@Michael Bạn có thể thêm câu trả lời đó làm câu trả lời khác nếu muốn. Hoặc tôi có thể thêm 'string_to_array' như là một tùy chọn trong tôi, không chắc chắn làm thế nào tôi bị mất. –

64

split_part() làm những gì bạn muốn trong một bước:

SELECT split_part(col, ',', 1) AS col1 
    , split_part(col, ',', 2) AS col2 
    , split_part(col, ',', 3) AS col3 
    , split_part(col, ',', 4) AS col4 
FROM tbl; 

Thêm vào làm nhiều dòng như bạn có các mục trong col (tối đa có thể). Các cột vượt quá các mục dữ liệu sẽ là các chuỗi rỗng ('').

+4

Và sẽ xuất hiện để thực hiện nhanh hơn rất nhiều so với phiên bản regexp_split_to_array. –

+0

@ JohnBarça: Tất cả các hàm biểu thức chính quy đều tương đối đắt tiền. Mạnh mẽ, nhưng với một mức giá ... –

+4

Truyền thuyết! Đây là cách tiếp cận nhanh nhất cho loại vấn đề này. –

1

Bạn có thể sử dụng chức năng chia tách.

SELECT 
    (select top 1 item from dbo.Split(FullName,',') where id=1) Column1, 
    (select top 1 item from dbo.Split(FullName,',') where id=2) Column2, 
    (select top 1 item from dbo.Split(FullName,',') where id=3) Column3, 
    (select top 1 item from dbo.Split(FullName,',') where id=4) Column4, 
    FROM MyTbl 
Các vấn đề liên quan