2012-12-11 15 views
5

Tôi đang sử dụng array_to_json kết hợp với array_agg để định dạng các kết quả nhất định trong PostgreSQL là JSON. Điều này làm việc tốt cho các truy vấn mà tôi muốn trả về giá trị mặc định của một truy vấn (tất cả các cột, chưa sửa đổi). Nhưng tôi stumped về cách tôi có thể sử dụng array_agg để tạo một đối tượng JSON cho một truy vấn mà tôi muốn sửa đổi một số đầu ra.Áp dụng array_agg/array_to_json cho một truy vấn với các cột đã sửa đổi

Đây là một ví dụ. Hãy nói rằng chúng tôi có như sau:

CREATE TABLE temp_user ( 
    user_id serial PRIMARY KEY, 
    real_name text 
); 
CREATE TABLE temp_user_ip (
    user_id integer, 
    ip_address text 
); 
INSERT INTO temp_user (user_id, real_name) VALUES (1, 'Elise'), (2, 'John'), (3, NULL); 
INSERT INTO temp_user_ip (user_id, ip_address) VALUES (1, '10.0.0.4'), (2, '10.0.0.7'), (3, '10.0.0.9'); 

Các truy vấn sau đây hoạt động tốt:

# SELECT array_to_json(array_agg(temp_user)) as users from temp_user; 
              users             
----------------------------------------------------------------------------------------------------- 
[{"user_id":1,"real_name":"Elise"},{"user_id":2,"real_name":"John"},{"user_id":3,"real_name":null}] 

Nhưng chúng ta hãy nói rằng tôi không thích những giá trị null xuất hiện cho người dùng 3. Tôi muốn thấy chuỗi "Người dùng đã đăng nhập từ $ ip" thay thế.

tôi có thể làm điều này:

# SELECT user_id, (CASE WHEN real_name IS NULL THEN (select 'User logged in from ' || ip_address FROM temp_user_ip WHERE user_id = temp_user.user_id) ELSE real_name END) as name from temp_user; 

Và tôi nhận được kết quả như sau:

user_id |    name    
---------+------------------------------ 
     1 | Elise 
     2 | John 
     3 | User logged in from 10.0.0.9 

Đó là tuyệt vời. Nhưng tôi không thể tìm ra cách để thao tác dữ liệu này thành định dạng JSON như ví dụ đầu tiên.

Các đầu ra mong muốn của khóa học là như sau:

[{"user_id":1,"name":"Elise"},{"user_id":2,"name":"John"},{"user_id":3,"name":"User logged in from 10.0.0.9"}] 

Sau đây không hoạt động:

# select array_to_json(array_agg ((SELECT user_id, (CASE WHEN real_name IS NULL THEN (select 'User logged in from ' || ip_address FROM temp_user_ip WHERE user_id = temp_user.user_id) ELSE real_name END) as name from temp_user))); 
ERROR: subquery must return only one column 

tôi không thể tìm ra cách nào để lấy dữ liệu sang một định dạng mà array_agg chấp nhận. Tôi thậm chí đã cố gắng tạo ra một loại tùy chỉnh phù hợp với định dạng của temp_user và cố gắng để array_agg cuộc gọi đến constructor loại, mà trả về cùng một lỗi. Lỗi không có ý nghĩa đối với tôi - nếu truy vấn con được tổng hợp, thì nó không thành vấn đề nếu nó trả về nhiều hơn một cột. Lời khuyên nào?

Trả lời

10

Bạn có thể tách các cuộc gọi tổng hợp từ các subquery và sử dụng các nhà xây dựng row để tạo ra các dữ liệu phức hợp:

SELECT 
    array_to_json(array_agg(row(t.*))) AS users 
FROM 
    (
     SELECT user_id, 
      CASE 
       WHEN real_name IS NULL 
       THEN (
        SELECT 'User logged in from ' || ip_address 
        FROM temp_user_ip 
        WHERE user_id = temp_user.user_id 
       ) ELSE real_name 
      END AS name 
     FROM temp_user 
    ) t 
; 

Bạn cũng có thể kiểm tra điều này trên SQLFiddle.

+1

Tôi có thể xác nhận tác phẩm này; Tôi vừa mới áp dụng phương thức này thành truy vấn thực sự của mình. Cảm ơn! – hs0

+7

Truy vấn có thể được đơn giản hóa một chút bằng cách thay thế 'array_agg (row (t. *))' Bằng cách đơn giản 'array_agg (t)'. Bằng cách đó bạn cũng giữ lại các tên cột từ truy vấn phụ. –

2

Chỉ cần một bản cập nhật tại đây, postgres giờ đây đã là một chức năng json_agg có thể được sử dụng trong leiu của array_to_json(array_agg(...)) nhưng thực sự cư xử tốt hơn trong một số trường hợp, xem tại đây: Array_agg in postgres selectively quotes

Documents: https://www.postgresql.org/docs/9.5/static/functions-aggregate.html

đây là sửa đổi truy vấn:

SELECT 
    json_agg(row(t.*)) AS users 
FROM 
    (
     SELECT user_id, 
      CASE 
       WHEN real_name IS NULL 
       THEN (
        SELECT 'User logged in from ' || ip_address 
        FROM temp_user_ip 
        WHERE user_id = temp_user.user_id 
       ) ELSE real_name 
      END AS name 
     FROM temp_user 
    ) t 
; 
+0

wow json_agg cực kỳ mạnh mẽ! – nicodjimenez

Các vấn đề liên quan