Tùy chỉnh thứ tự sắp xếp khóa jsonb liên quan đến mảng


9

Tôi có một bảng trong PostgreSQL với một số dữ liệu:

create table t2 (
    key jsonb,
    value jsonb
);

INSERT INTO t2(key, value)
 VALUES
 ('1', '"test 1"')
,('2', '"test 2"')
,('3', '"test 3"')
,('[]', '"test 4"')
,('[1]', '"test 5"')
,('[2]', '"test 6"')
,('[3]', '"test 7"')
,('[1, 2]', '"test 8"')
,('[1, 2, 3]', '"test 9"')
,('[1, 3]', '"test 10"')
,('[1,2,4]', '"test 11"')
,('[1, 2,4]', '"test 12"')
,('[1,3,13]', '"test 13"')
,('[1, 2, 15]', '"test 15"');

Và tôi cố gắng sắp xếp các hàng như thế:

SELECT key FROM t2 order by key;

Kết quả là:

[]
1
2
3
[1]
[2] <==
[3] <==
[1, 2]
[1, 3] <==
[1, 2, 3]
[1, 2, 4]
[1, 2, 4]
[1, 2, 15]
[1, 3, 13]

Nhưng cái tôi cần là:

[]
1
2
3
[1]
[1, 2]
[1, 2, 3]
[1, 2, 4]
[1, 2, 4]
[1, 2, 15]
[1, 3] <==
[1, 3, 13]
[2] <==
[3] <==

Có cách nào để đạt được nó?


Vì vậy, bạn có câu trả lời của bạn ở đây?
Erwin Brandstetter

Câu trả lời:


8

Trước hết, câu hỏi cũng như tên cột của bạn "key"là sai lệch. Khóa cột không chứa bất kỳ khóa JSON nào , chỉ có các giá trị . Khác chúng ta có thể sử dụng chức năng jsonb_object_keys(jsonb)để trích xuất các khóa, nhưng đó không phải là như vậy.

Giả sử tất cả các mảng JSON của bạn trống hoặc giữ các số nguyên như đã trình bày. Và các giá trị vô hướng (không phải mảng) cũng là số nguyên.

Thứ tự sắp xếp cơ bản của bạn sẽ hoạt động với mảng Postgres integer(hoặc numeric). Tôi sử dụng chức năng trợ giúp nhỏ này để chuyển đổi jsonbmảng thành Postgres int[]:

CREATE OR REPLACE FUNCTION jsonb_arr2int_arr(_js jsonb)
   RETURNS int[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY(SELECT j::int FROM jsonb_array_elements_text(_js) j)';

Giải trình:

Sau đó thêm jsonb_typeof(jsonb)để đến:

SELECT key
FROM   t2
ORDER  BY key <> '[]'             -- special case for empty array
        , jsonb_typeof(key) DESC  -- 'number' before 'array'
        , CASE jsonb_typeof(key)  -- sort arrays as converted int[]
            WHEN 'array'  THEN jsonb_arr2int_arr(key)
            WHEN 'number' THEN ARRAY[key::text::int]
          END;

Tạo ra kết quả mong muốn chính xác.

Tại sao?

Hướng dẫn jsonbgiải thích:

Thứ btreetự cho các jsonbdatum hiếm khi được quan tâm, nhưng để hoàn thiện nó là:

Object > Array > Boolean > Number > String > Null
Object with n pairs > object with n - 1 pairs
Array with n elements > array with n - 1 elements

Các đối tượng có số cặp bằng nhau được so sánh theo thứ tự:

key-1, value-1, key-2 ...

Lưu ý rằng các khóa đối tượng được so sánh theo thứ tự lưu trữ của chúng; đặc biệt, vì các khóa ngắn hơn được lưu trữ trước các khóa dài hơn, điều này có thể dẫn đến các kết quả có thể không trực quan, chẳng hạn như:

{ "aa": 1, "c": 1} > {"b": 1, "d": 1}

Tương tự, các mảng có số phần tử bằng nhau được so sánh theo thứ tự:

element-1, element-2 ...

Nhấn mạnh đậm của tôi.
Đó là lý do tại sao jsonb '[2]' < jsonb '[1, 2]'.
Nhưng mảng Postgres chỉ sắp xếp từng yếu tố: '{2}'::int[] > '{1, 2}'- chính xác những gì bạn đang tìm kiếm.


0

Đề cập đến vấn đề để sắp xếp kết quả của bạn bằng các giá trị nguyên json. Thử:

select myjson from mytable order by (myjson->>'some_int')::int;

Trong trường hợp của bạn, nó dường như là một mảng cho khóa đặt hàng. Vì vậy, trước tiên hãy thử nối các giá trị trong trường "khóa" của bạn.

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.