2014-07-26 12 views
10

Tôi có một bảng temp định nghĩa như thế này:Làm cách nào để đặt tên thuộc tính chính xác thành kết quả tổng hợp json với mệnh đề GROUP BY?

id | name | body | group_id 
------------------------------- 
1 | test_1 | body_1 | 1 
2 | test_2 | body_2 | 1 
3 | test_3 | body_3 | 2 
4 | test_4 | body_4 | 2 

Tôi muốn tạo ra một kết quả phân nhóm theo group_id và tổng hợp để json. Tuy nhiên, truy vấn như thế này:

SELECT group_id, json_agg(ROW(id, name, body)) FROM temp 
GROUP BY group_id; 

Tạo kết quả này:

1;[{"f1":1,"f2":"test_1","f3":"body_1"}, 
    {"f1":2,"f2":"test_2","f3":"body_2"}] 
2;[{"f1":3,"f2":"test_3","f3":"body_3"}, 
    {"f1":4,"f2":"test_4","f3":"body_4"}] 

Các thuộc tính trong các đối tượng json được đặt tên f1, f2, f3 thay vì id, name, body theo yêu cầu. Tôi biết nó có thể bí danh họ đúng cách bằng cách sử dụng một subquery hoặc một biểu thức bảng chung, ví dụ như thế này:

SELECT json_agg(r.*) FROM (
    SELECT id, name, body FROM temp 
) r; 

nào tạo ra kết quả này:

[{"id":1,"name":"test_1","body":"body_1"}, 
{"id":2,"name":"test_2","body":"body_2"}, 
{"id":3,"name":"test_3","body":"body_3"}, 
{"id":4,"name":"test_4","body":"body_4"}] 

Nhưng tôi thật không thấy bất kỳ cách nào để sử dụng nó kết hợp với tập hợp. Tôi đang thiếu gì?

Trả lời

15

Bạn không cần bảng tạm thời hoặc loại cho điều này, nhưng nó không đẹp.

SELECT json_agg(row_to_json((SELECT r FROM (SELECT id, name, body) r))) 
FROM t 
GROUP BY group_id; 

Ở đây, chúng tôi sử dụng hai truy vấn phụ - trước tiên, để tạo tập hợp kết quả chỉ với ba cột mong muốn, sau đó truy vấn con bên ngoài để tạo nó thành một hàng kiểu hỗn hợp.

Nó vẫn hoạt động tốt.


Đối với điều này được thực hiện với cú pháp ít xấu xí, PostgreSQL sẽ cần phải cho phép bạn đặt bí danh cho rowtypes mang tính chất như (không hợp lệ) cú pháp sau:

SELECT json_agg(row_to_json(ROW(id, name, body) AS (id, name, body))) 
FROM t 
GROUP BY group_id; 

hoặc chúng tôi cần một biến thể của row_to_json rằng mất bí danh cột, giống như (một lần nữa không hợp lệ):

SELECT json_agg(row_to_json(ROW(id, name, body), ARRAY['id', 'name', 'body'])) 
FROM t 
GROUP BY group_id; 

hoặc/cả hai trong số đó sẽ được tốt đẹp, nhưng hiện không được hỗ trợ.

+0

Không thực sự thanh lịch nhưng trông khá đơn giản, trên thực tế quá đơn giản để tôi thậm chí còn cân nhắc điều này ngay từ đầu, cảm ơn! – Przemek

0

Vâng, trả lời câu hỏi của riêng tôi vài phút sau khi hỏi nhưng tôi đã tìm được cách ... Tôi không biết đó là câu hỏi hay nhất. Tôi giải quyết nó bằng cách tạo ra một loại hỗn hợp:

CREATE TYPE temp_type AS (
    id bigint, 
    name text, 
    body text 
); 

Và viết lại truy vấn của tôi bằng cách thêm một dàn diễn viên để kiểu:

SELECT group_id, json_agg(CAST(ROW(id, name, body) AS temp_type)) FROM temp 
GROUP BY group_id; 

nào sản xuất các kết quả mong đợi:

1;[{"id":1,"name":"test_1","body":"body_1"}, 
    {"id":2,"name":"test_2","body":"body_2"}] 
2;[{"id":3,"name":"test_3","body":"body_3"}, 
    {"id":4,"name":"test_4","body":"body_4"}] 
2

tôi chỉ cần đăng một giải pháp rất giống to yours chỉ sử dụng bảng tạm thời

create table t (
    id int, 
    name text, 
    body text, 
    group_id int 
); 
insert into t (id, name, body, group_id) values 
(1, 'test_1', 'body_1', 1), 
(2, 'test_2', 'body_2', 1), 
(3, 'test_3', 'body_3', 2), 
(4, 'test_4', 'body_4', 2); 

create temporary table tt(
    id int, 
    name text, 
    body text 
); 

select group_id, json_agg(row(id, name, body)::tt) 
from t 
group by group_id; 
group_id |     json_agg     
----------+--------------------------------------------- 
     1 | [{"id":1,"name":"test_1","body":"body_1"}, + 
      | {"id":2,"name":"test_2","body":"body_2"}] 
     2 | [{"id":3,"name":"test_3","body":"body_3"}, + 
      | {"id":4,"name":"test_4","body":"body_4"}] 
4

xây dựng trên @Craig's answer để làm cho nó trở nên thanh lịch, ở đây ROWTYPE tổng hợp được xây dựng trong from danh sách

select json_agg(row_to_json(s)) 
from 
    t 
    cross join lateral 
    (select id, name, body) s 
group by group_id; 
             json_agg          
-------------------------------------------------------------------------------------- 
[{"id":1,"name":"test_1","body":"body_1"}, {"id":2,"name":"test_2","body":"body_2"}] 
[{"id":3,"name":"test_3","body":"body_3"}, {"id":4,"name":"test_4","body":"body_4"}] 
21

Trong Postgres 9.4 bạn có thể sử dụng json_build_object().

Ví dụ của bạn, nó hoạt động như:

SELECT group_id, 
     json_agg(json_build_object('id', id, 'name', name, 'body', body)) 
FROM temp 
GROUP BY group_id; 

đây là một cách thân thiện hơn, Postgres yêu thương chúng ta: 3

1

Nếu bạn cần tất cả các lĩnh vực từ bảng, sau đó bạn có thể sử dụng phương pháp này:

SELECT 
    group_id, json_agg(temp.*) 
FROM 
    temp 
GROUP BY 
    group_id; 
Các vấn đề liên quan