Postgresql GROUP_CONCAT tương đương?


247

Tôi có một bảng và tôi muốn kéo một hàng cho mỗi id với các giá trị trường được nối.

Trong bảng của tôi, ví dụ, tôi có cái này:

TM67 | 4  | 32556
TM67 | 9  | 98200
TM67 | 72 | 22300
TM99 | 2  | 23009
TM99 | 3  | 11200

Và tôi muốn xuất ra:

TM67 | 4,9,72 | 32556,98200,22300
TM99 | 2,3    | 23009,11200

Trong MySQL tôi đã có thể sử dụng hàm tổng hợp GROUP_CONCAT, nhưng dường như nó không hoạt động ở đây ... Có tương đương với PostgreQuery hay cách nào khác để thực hiện điều này không?


Không phải là một câu trả lời, nhưng hãy kiểm tra postgresonline.com/journal/index.php?/archives/iêu .
Kuberchaun



1
Tôi nghĩ rằng câu trả lời tốt nhất vẫn là trong một câu hỏi khác: stackoverflow.com/a/47638417/243233
Jus12

Câu trả lời:


237

Đây có lẽ là một điểm khởi đầu tốt (chỉ phiên bản 8.4+):

SELECT id_field, array_agg(value_field1), array_agg(value_field2)
FROM data_table
GROUP BY id_field

mảng_agg trả về một mảng, nhưng bạn có thể CAST đó để nhắn tin và chỉnh sửa khi cần (xem phần làm rõ bên dưới).

Trước phiên bản 8.4, bạn phải tự xác định trước khi sử dụng:

CREATE AGGREGATE array_agg (anyelement)
(
    sfunc = array_append,
    stype = anyarray,
    initcond = '{}'
);

(diễn giải từ tài liệu PostgreQuery)

Làm rõ:

  • Kết quả của việc truyền một mảng thành văn bản là chuỗi kết quả bắt đầu và kết thúc bằng dấu ngoặc nhọn. Những niềng răng cần phải được loại bỏ bằng một số phương pháp, nếu chúng không mong muốn.
  • Truyền ANYARRAY sang văn bản mô phỏng tốt nhất đầu ra CSV vì các thành phần có chứa dấu phẩy nhúng được trích dẫn kép trong đầu ra theo kiểu CSV tiêu chuẩn. Cả Array_to_opes () hoặc string_agg () (hàm "group_concat" được thêm vào 9.1) với các dấu phẩy được nhúng, dẫn đến số phần tử không chính xác trong danh sách kết quả.
  • Hàm 9.1 chuỗi_agg () mới KHÔNG tạo kết quả bên trong thành văn bản trước. Vì vậy, "string_agg (value_field)" sẽ tạo ra lỗi nếu value_field là một số nguyên. "string_agg (value_field :: text)" sẽ được yêu cầu. Phương thức Array_agg () chỉ yêu cầu một lần truyền sau khi tổng hợp (chứ không phải là truyền trên mỗi giá trị).

1
Và trong 9.0 bạn sẽ có listagg ()
Scott Bailey

6
Để nhận CSV, truy vấn phải là: SELECT id_field, Array_to_opes (Array_agg (value_field1), ','), Array_to_opes (Array_agg (value_field2), ',') TỪ data_table GROUP BY id_field
Nux

2
Bạn không thể sử dụng Array_to_opes trong mọi trường hợp ở đây. Nếu value_field của bạn chứa dấu phẩy được nhúng, CSV kết quả không chính xác. Sử dụng mảng_agg () và truyền vào văn bản trích dẫn chính xác chuỗi bằng dấu phẩy được nhúng. Nhắc nhở duy nhất là nó cũng bao gồm các dấu ngoặc nhọn bắt đầu và kết thúc, do đó tuyên bố của tôi "và chỉnh sửa khi cần thiết". Tôi sẽ chỉnh sửa để làm rõ điểm đó.
Matthew Wood

FYI: đây là một liên kết đến các tài liệu trên mảng_agg trong 8.4
Michael Rusch

255

Kể từ 9.0, điều này thậm chí còn dễ dàng hơn:

SELECT id, 
       string_agg(some_column, ',')
FROM the_table
GROUP BY id

32
Lưu ý rằng cú pháp cũng cho phép bạn chỉ định thứ tự các giá trị trong chuỗi (hoặc mảng, sử dụng array_agg), vd string_agg(some_column, ',' ORDER BY some_column)hoặc thậm chístring_agg(surname || ', ' || forename, '; ' ORDER BY surname, forename)
IMSoP

8
Thật tuyệt vời khi distincthoạt động với string_agg, vì vậy người ta có thể sử dụngstring_agg(distinct some_solumn, ',')
arun

3
Lưu ý rằng bạn có thể cần truyền giá trị cột thành TEXTnếu đó là giá trị không thể xâu chuỗi (ví dụ. uuid). Điều này sẽ giống nhưstring_agg(some_column::text, ',')
Kendall

48
SELECT array_to_string(array(SELECT a FROM b),', ');

Sẽ làm như vậy.


Có thể làm một cái gì đó như trong bình luận này , nơi bạn tổng hợp theo một thứ tự nhất định? Làm thế nào bạn có thể xử lý việc nhóm theo một cột và sắp xếp theo một cột khác (ví dụ: để ghép các biến trong một tập dữ liệu theo chiều dọc)?
Michael A

15

Hãy thử như thế này:

select field1, array_to_string(array_agg(field2), ',')
from table1
group by field1;

2

và phiên bản để làm việc trên kiểu mảng :

select
  array_to_string(
    array(select distinct unnest(zip_codes) from table),
    ', '
);

Câu trả lời trùng lặp, @max_spy đã nói điều tương tự năm năm trước
Emil Vikström

@ EmilVikström: bạn có quyền sai, nhưng hãy đọc kỹ. Nó không chỉ khác nhau, mà tôi đã đưa ra một ví dụ, hoạt động với kiểu mảng - giống như zip_codes character varying(5)[]. Ngoài ra, tôi đã xác minh rằng với mục đích của tôi - không cần thiết, nếu không bạn sẽ thấy ERROR: cannot accumulate arrays of different dimensionality.
Sławomir Lenart

1

Sự ngăn chặn của tôi trong postgresql

SELECT cpf || ';' || nome || ';' || telefone  
FROM (
      SELECT cpf
            ,nome
            ,STRING_AGG(CONCAT_WS( ';' , DDD_1, TELEFONE_1),';') AS telefone 
      FROM (
            SELECT DISTINCT * 
            FROM temp_bd 
            ORDER BY cpf DESC ) AS y
      GROUP BY 1,2 ) AS x   

1
Tại sao bạn làm ORDER BYtrong một truy vấn bên trong? Sẽ không có thứ tự bị mất?
mypetlion

-1

Hy vọng dưới đây truy vấn Oracle sẽ làm việc.

Select First_column,LISTAGG(second_column,',') 
    WITHIN GROUP (ORDER BY second_column) as Sec_column, 
    LISTAGG(third_column,',') 
    WITHIN GROUP (ORDER BY second_column) as thrd_column 
FROM tablename 
GROUP BY first_column

Tôi đã thử nghiệm nó trên rextester.com/l/postgresql_online_compiler và không hoạt động: 42883: hàm listagg (văn bản, không xác định, văn bản) không tồn tại
Manuel Romeiro

Oracle có cú pháp và chức năng khác với postgres.
Herman J. Radtke III
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.