PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Sử dụng row_to_json () với các phép nối lồng nhau

Cập nhật:Trong PostgreSQL 9.4, điều này được cải thiện rất nhiều với sự ra đời của to_json , json_build_object , json_objectjson_build_array , mặc dù nó dài dòng do cần phải đặt tên cho tất cả các trường một cách rõ ràng:

select
        json_build_object(
                'id', u.id,
                'name', u.name,
                'email', u.email,
                'user_role_id', u.user_role_id,
                'user_role', json_build_object(
                        'id', ur.id,
                        'name', ur.name,
                        'description', ur.description,
                        'duty_id', ur.duty_id,
                        'duty', json_build_object(
                                'id', d.id,
                                'name', d.name
                        )
                )
    )
from users u
inner join user_roles ur on ur.id = u.user_role_id
inner join role_duties d on d.id = ur.duty_id;

Đối với các phiên bản cũ hơn, hãy đọc tiếp.

Nó không giới hạn ở một hàng duy nhất, nó chỉ hơi đau một chút. Bạn không thể đặt bí danh cho các kiểu hàng tổng hợp bằng cách sử dụng AS , vì vậy bạn cần sử dụng biểu thức truy vấn con bí danh hoặc CTE để đạt được hiệu quả:

select row_to_json(row)
from (
    select u.*, urd AS user_role
    from users u
    inner join (
        select ur.*, d
        from user_roles ur
        inner join role_duties d on d.id = ur.duty_id
    ) urd(id,name,description,duty_id,duty) on urd.id = u.user_role_id
) row;

sản xuất, thông qua http://jsonprettyprint.com/:

{
  "id": 1,
  "name": "Dan",
  "email": "[email protected]",
  "user_role_id": 1,
  "user_role": {
    "id": 1,
    "name": "admin",
    "description": "Administrative duties in the system",
    "duty_id": 1,
    "duty": {
      "id": 1,
      "name": "Script Execution"
    }
  }
}

Bạn sẽ muốn sử dụng array_to_json(array_agg(...)) khi bạn có mối quan hệ 1:nhiều, btw.

Lý tưởng nhất là truy vấn trên có thể được viết là:

select row_to_json(
    ROW(u.*, ROW(ur.*, d AS duty) AS user_role)
)
from users u
inner join user_roles ur on ur.id = u.user_role_id
inner join role_duties d on d.id = ur.duty_id;

... nhưng ROW của PostgreSQL hàm tạo không chấp nhận AS bí danh cột. Thật đáng buồn.

Rất may, họ tối ưu hóa giống nhau. So sánh các kế hoạch:

  • Phiên bản truy vấn con lồng nhau; so với
  • ROW lồng nhau sau phiên bản phương thức khởi tạo với bí danh bị xóa để nó thực thi

Vì CTE là hàng rào tối ưu hóa, nên việc diễn đạt lại phiên bản truy vấn con lồng nhau để sử dụng CTE chuỗi (WITH biểu thức) cũng có thể không hoạt động và sẽ không dẫn đến cùng một kế hoạch. Trong trường hợp này, bạn đang gặp khó khăn với các truy vấn con lồng nhau xấu xí cho đến khi chúng tôi nhận được một số cải tiến đối với row_to_json hoặc một cách để ghi đè tên cột trong ROW hàm tạo trực tiếp hơn.

Nói chung, nguyên tắc là nơi bạn muốn tạo một đối tượng json với các cột a, b, c và bạn ước mình có thể viết cú pháp không hợp lệ:

ROW(a, b, c) AS outername(name1, name2, name3)

thay vào đó, bạn có thể sử dụng truy vấn con vô hướng trả về giá trị được nhập theo hàng:

(SELECT x FROM (SELECT a AS name1, b AS name2, c AS name3) x) AS outername

Hoặc:

(SELECT x FROM (SELECT a, b, c) AS x(name1, name2, name3)) AS outername

Ngoài ra, hãy nhớ rằng bạn có thể soạn json các giá trị mà không cần trích dẫn bổ sung, ví dụ:nếu bạn đặt đầu ra của một json_agg trong một row_to_json , json_agg bên trong kết quả sẽ không được trích dẫn dưới dạng một chuỗi, nó sẽ được kết hợp trực tiếp dưới dạng json.

ví dụ. trong ví dụ tùy ý:

SELECT row_to_json(
        (SELECT x FROM (SELECT
                1 AS k1,
                2 AS k2,
                (SELECT json_agg( (SELECT x FROM (SELECT 1 AS a, 2 AS b) x) )
                 FROM generate_series(1,2) ) AS k3
        ) x),
        true
);

đầu ra là:

{"k1":1,
 "k2":2,
 "k3":[{"a":1,"b":2}, 
 {"a":1,"b":2}]}

Lưu ý rằng json_agg product, [{"a":1,"b":2}, {"a":1,"b":2}] , đã không được thoát lại, dưới dạng text sẽ là.

Điều này có nghĩa là bạn có thể soạn các hoạt động json để tạo các hàng, bạn không phải lúc nào cũng phải tạo các kiểu kết hợp PostgreSQL cực kỳ phức tạp, sau đó gọi row_to_json trên đầu ra.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Đặt lại khóa chính PostgreSQL thành 1

  2. Cách thay đổi mã hóa bộ sưu tập cơ sở dữ liệu mẫu

  3. Postgres không sử dụng chỉ mục khi quét chỉ mục là tùy chọn tốt hơn nhiều

  4. Chia tỷ lệ theo chiều dọc PostgreSQL

  5. Không tìm thấy hàm chuyển đổi từ không xác định thành văn bản