Truy vấn JSONB trong PostgreSQL


13

Tôi có một bảng, personschứa hai cột, một cột iddựa trên JSONB data(bảng này vừa được tạo cho mục đích trình diễn để chơi xung quanh với sự hỗ trợ JSON của PostgreQuery).

Bây giờ, giả sử nó chứa hai bản ghi:

1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }

Bây giờ, giả sử tôi muốn có được tên của mọi người trên 25. Điều tôi đã thử là:

select data->'name' as name from persons where data->'age' > 25

Thật không may, điều này dẫn đến một lỗi. Tôi có thể giải quyết nó bằng cách sử dụng ->>thay vì ->, nhưng sau đó các phép so sánh không hoạt động như mong đợi nữa, vì không phải là các số được so sánh, mà là các đại diện của chúng dưới dạng chuỗi:

select data->'name' as name from persons where data->>'age' > '25'

Sau đó tôi đã tìm ra rằng tôi thực sự có thể giải quyết vấn đề bằng cách sử dụng ->và chọn một int:

select data->'name' as name from persons where cast(data->'age' as int) > 25

Điều này hoạt động, nhưng thật tuyệt khi tôi phải biết loại thực tế (loại agetrong tài liệu JSON là numberdù sao, vậy tại sao PostgreQuery không thể tự mình tìm ra điều đó?).

Sau đó tôi đã nhận ra rằng nếu tôi chuyển đổi thủ công sang textsử dụng ::cú pháp, mọi thứ cũng hoạt động như mong đợi - mặc dù hiện tại chúng tôi đang so sánh các chuỗi một lần nữa.

select data->'name' as name from persons where data->'age'::text > '25'

Nếu sau đó tôi thử cái này với tên thay vì tuổi, nó không hoạt động:

select data->'name' as name from persons where data->'name'::text > 'Jenny'

Điều này dẫn đến một lỗi:

cú pháp nhập không hợp lệ cho loại json

Rõ ràng, tôi không nhận được một cái gì đó ở đây. Thật không may, thật khó để tìm thấy bất kỳ ví dụ thực tế nào về việc sử dụng JSON với PostgreSQL.

Có gợi ý nào không?


1
Trong data->'name'::text, bạn đang truyền 'name'chuỗi thành văn bản, không phải kết quả. Bạn không gặp lỗi khi so sánh '25'25là một chữ JSON hợp lệ; nhưng Jennykhông phải (mặc dù "Jenny"sẽ được).
chirlu

Cảm ơn, đó là giải pháp :-). Tôi bối rối 'Jenny'với '"Jenny"'.
Golo Roden

Câu trả lời:


14

Điều này không hoạt động vì nó đang cố gắng đưa ra một jsonbgiá trị integer.

select data->'name' as name from persons where cast(data->'age' as int) > 25

Điều này thực sự sẽ làm việc:

SELECT data->'name' AS name FROM persons WHERE cast(data->>'age' AS int) > 25;

Hoặc ngắn hơn:

SELECT data->'name' AS name FROM persons WHERE (data->>'age')::int > 25;

Và điều này:

SELECT data->'name' AS name FROM persons WHERE data->>'name' > 'Jenny';

Có vẻ như nhầm lẫn với hai nhà khai thác ->->>điều hành được ưu tiên . Các diễn viên ::liên kết mạnh hơn các toán tử json (b).

Tìm ra kiểu động

Đây là phần thú vị hơn trong câu hỏi của bạn:

loại tuổi trong tài liệu JSON là số dù sao, vậy tại sao PostgreQuery không thể tự mình tìm ra điều đó?

SQL là một ngôn ngữ được gõ đúng, nó không cho phép cùng một biểu thức để đánh giá integertrong một hàng và texttrong hàng tiếp theo. Nhưng vì bạn chỉ quan tâm đến booleankết quả của bài kiểm tra, bạn có thể vượt qua giới hạn này bằng một CASEbiểu thức rèn tùy thuộc vào kết quả của jsonb_typeof():

SELECT data->'name'
FROM   persons
WHERE  CASE jsonb_typeof(data->'age')
        WHEN 'number'  THEN (data->>'age')::numeric > '25' -- treated as numeric
        WHEN 'string'  THEN data->>'age' > 'age_level_3'   -- treated as text
        WHEN 'boolean' THEN (data->>'age')::bool           -- use boolean directly (example)
        ELSE FALSE                                         -- remaining: array, object, null
       END;

Một chuỗi ký tự không được đánh dấu ở bên phải của >toán tử được tự động ép buộc với loại giá trị tương ứng ở bên trái. Nếu bạn đặt một giá trị được nhập vào đó, loại phải khớp hoặc bạn phải sử dụng nó một cách rõ ràng - trừ khi có đầy đủ diễn viên ẩn được đăng ký trong hệ thống.

Nếu bạn biết rằng tất cả các giá trị số thực sự integer, bạn cũng có thể:

... (data->>'age')::int > 25 ...

biểu thức cốt lõi sqlalchemy là gì để so sánh ở trên của câu lệnh select, vd. s = select ([vấn đề]). trong đó (vấn đề.c.id == mid) .select_from (vấn đề, ..... outsjoin (vấn đề ) ... Ở đây vấn đề.c.data jsonb loại dữ liệu và đang được so sánh với mtypes.c.id của loại số nguyên
user956424
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.