กำหนดลำดับการจัดเรียงคีย์ jsonb ที่เกี่ยวข้องกับอาร์เรย์


9

ฉันมีตารางใน PostgreSQL พร้อมข้อมูลบางส่วน:

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"');

และฉันพยายามเรียงแถวเหล่านี้แบบนั้น:

SELECT key FROM t2 order by key;

ผลลัพธ์คือ:

[]
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]

แต่สิ่งที่ฉันต้องการคือ:

[]
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] <==

มีวิธีในการบรรลุหรือไม่


คุณมีคำตอบที่นี่ไหม?
Erwin Brandstetter

คำตอบ:


8

ก่อนอื่นคำถามของคุณและชื่อคอลัมน์"key"จะทำให้เข้าใจผิด กุญแจสำคัญในคอลัมน์นี้ไม่ได้มีการใด ๆ JSON ปุ่มเพียงค่า มิฉะนั้นเราสามารถใช้ฟังก์ชั่นjsonb_object_keys(jsonb)เพื่อแยกกุญแจได้ แต่นั่นไม่ใช่อย่างนั้น

สมมติว่าอาร์เรย์ JSON ทั้งหมดของคุณว่างเปล่าหรือถือตัวเลขจำนวนเต็มตามที่แสดง และค่าสเกลาร์ (ไม่ใช่อาร์เรย์) ก็เป็นจำนวนเต็มเช่นกัน

การเรียงลำดับพื้นฐานของคุณจะทำงานกับอาร์เรย์Postgres integer(หรือnumeric) ฉันใช้ฟังก์ชันตัวช่วยเล็กน้อยนี้เพื่อแปลงjsonbอาร์เรย์เป็น 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)';

คำอธิบาย:

จากนั้นเพิ่มjsonb_typeof(jsonb)มาถึงที่:

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;

สร้างผลลัพธ์ที่ต้องการอย่างแน่นอน

ทำไม?

คู่มือสำหรับjsonbอธิบาย:

การbtreeสั่งซื้อjsonbข้อมูลนั้นไม่ค่อยได้รับความสนใจมากนัก แต่เพื่อความสมบูรณ์มันคือ:

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

วัตถุที่มีจำนวนคู่เท่ากันจะถูกเปรียบเทียบในลำดับ:

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

โปรดทราบว่าคีย์วัตถุถูกเปรียบเทียบในลำดับการจัดเก็บ โดยเฉพาะอย่างยิ่งเนื่องจากมีการจัดเก็บคีย์ที่สั้นกว่าก่อนคีย์ที่ยาวกว่าสิ่งนี้อาจนำไปสู่ผลลัพธ์ที่อาจไม่ได้ใช้งานง่ายเช่น:

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

ในทำนองเดียวกันอาร์เรย์ที่มีจำนวนองค์ประกอบเท่ากันจะถูกเปรียบเทียบในลำดับ:

element-1, element-2 ...

เหมืองเน้นหนัก นั่นเป็นเหตุผลที่
แต่อาร์เรย์ Postgres เพียงเรียงลำดับองค์ประกอบโดยองค์ประกอบ: - สิ่งที่คุณกำลังมองหาjsonb '[2]' < jsonb '[1, 2]'
'{2}'::int[] > '{1, 2}'


0

อ้างถึงปัญหาในการสั่งซื้อผลลัพธ์ของคุณด้วยค่าจำนวนเต็ม json ลอง:

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

ในกรณีของคุณดูเหมือนว่าจะเป็นอาร์เรย์สำหรับคีย์การสั่งซื้อ ดังนั้นก่อนอื่นให้พยายามต่อค่าในฟิลด์ "คีย์" ของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.