2015-05-16 21 views
5

Lưu ý: Tôi đang sử dụng phiên bản mới nhất của Postgres (9,4)Làm thế nào để kết hợp DISTINCT và ORDER BY trong array_agg các giá trị jsonb trong Postgressql

Tôi cố gắng để viết một truy vấn mà không tham gia vào một đơn giản của 2 bảng, và các nhóm bằng khóa chính của bảng đầu tiên, và thực hiện một mảng_agg của một số trường trong bảng thứ hai mà tôi muốn trả về dưới dạng một đối tượng. Mảng này cần phải được sắp xếp theo sự kết hợp của 2 trường trong các đối tượng json, và cũng không được thống nhất.

Cho đến nay, tôi đã đưa ra như sau:

SELECT 
    zoo.id, 
    ARRAY_AGG(
    DISTINCT ROW_TO_JSON(( 
     SELECT x 
     FROM ( 
     SELECT animals.type, animals.name 
    ) x 
    ))::JSONB 
    -- ORDER BY animals.type, animals.name 
) 
    FROM zoo 
    JOIN animals ON animals.zooId = zoo.id 
    GROUP BY zoo.id; 

Điều này dẫn đến một hàng cho mỗi vườn thú, với một mảng tổng hợp của các đối tượng jsonb, một cho mỗi động vật, độc đáo.

Tuy nhiên, tôi dường như không thể tìm ra cách cũng sắp xếp điều này theo các tham số trong phần nhận xét của mã.

Nếu tôi đưa ra sự khác biệt, tôi có thể ORDER BY trường gốc, hoạt động tốt, nhưng sau đó tôi có bản sao.

+0

Bạn có thể cung cấp một số dữ liệu mẫu và đầu ra mong muốn không? – Eggplant

Trả lời

2

Nếu bạn sử dụng row_to_json(), bạn sẽ mất tên cột trừ khi bạn đặt hàng liên tiếp được nhập. Nếu bạn "bằng tay" xây dựng các đối tượng jsonb với json_build_object() sử dụng tên rõ ràng sau đó bạn nhận được chúng trở lại:

SELECT zoo.id, array_agg(za.jb) AS animals 
FROM zoo 
JOIN (
    SELECT DISTINCT ON (zooId, "type", "name") 
    zooId, json_build_object('animal_type', "type", 'animal_name', "name")::jsonb AS jb 
    FROM animals 
    ORDER BY zooId, jb->>'animal_type', jb->>'animal_name' 
    -- ORDER BY zooId, "type", "name" is far more efficient 
) AS za ON za.zooId = zoo.id 
GROUP BY zoo.id; 

Bạn có thể ORDER BY các yếu tố của một đối tượng jsonb, như trình bày ở trên, nhưng (như xa như tôi biết), bạn không thể sử dụng DISTINCT trên đối tượng jsonb. Trong trường hợp của bạn, điều này sẽ khá kém hiệu quả (đầu tiên xây dựng tất cả các đối tượng jsonb, sau đó ném ra các bản sao) và ở cấp độ tổng thể, nó là không thể với SQL chuẩn. Tuy nhiên, bạn có thể đạt được kết quả tương tự, bằng cách áp dụng mệnh đề DISTINCT trước khi tạo đối tượng jsonb.

Ngoài ra, tránh sử dụng SQL key words như "loại" và các loại dữ liệu chuẩn như "tên" làm tên cột. Cả hai đều là từ khóa không dành riêng để bạn có thể sử dụng chúng trong ngữ cảnh thích hợp của chúng, nhưng thực tế việc nói lệnh của bạn có thể rất khó hiểu. Bạn có thể, ví dụ, có một lược đồ, với một bảng, một cột trong bảng đó, và một kiểu dữ liệu mỗi gọi là "type" và sau đó bạn có thể có được điều này:

SELECT type::type FROM type.type WHERE type = something; 

Trong khi PostgreSQL sẽ ân cần chấp nhận điều này, nó là đồng bằng khó hiểu ở tốt nhất và dễ bị lỗi trong tất cả các loại tình huống phức tạp hơn. Bạn có thể nhận được một chặng đường dài bằng cách trích dẫn hai từ bất kỳ từ khóa nào, nhưng tốt nhất là bạn nên tránh làm định danh.

+0

Vì truy vấn tôi cung cấp thực sự là một tập hợp con của truy vấn lớn hơn (mà tôi đã giảm cho đơn giản trong việc đặt câu hỏi), tôi quên có một WHERE trên tham số của bảng sở thú. Đối với truy vấn bạn cung cấp, điều đó sẽ giải quyết được vấn đề, nhưng nó vẫn không trả lời được câu hỏi chính mà tôi có, có thể kết hợp DISTINCT và ORDER BY trong tổng hợp các giá trị JSONB đã tạo hay không (một trong hai dường như hoạt động tốt). Ngoài ra, bạn có thể vui lòng giải thích về việc sử dụng "tên" và "loại" không? Đây có phải là vấn đề trong bưu điện hay chỉ nói chung? – Philberg

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