Dizileri içeren jsonb anahtar sıralama düzenini özelleştirin


9

PostgreSQL bazı verilerle bir tablo var:

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

Ve bu satırları şöyle sıralamaya çalışıyorum:

SELECT key FROM t2 order by key;

Sonuç:

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

Ama ihtiyacım olan şey:

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

Bunu başarmanın bir yolu var mı?


Burada cevabınız var mı?
Erwin Brandstetter

Yanıtlar:


8

Öncelikle, sorunuzun yanı sıra sütun adınız "key"da yanıltıcı. Sütun anahtarı herhangi bir JSON anahtarı içermez , yalnızca değerler içerir . jsonb_object_keys(jsonb)Yoksa işlevi anahtarları ayıklamak için kullanabiliriz , ama öyle değil.

Tüm JSON dizilerinizin boş olduğu varsayılarak gösterildiği gibi tamsayı sayıları tutulur. Ve skaler değerler (diziler dışında) da tamsayıdır.

Temel sıralama düzeniniz Postgres integer(veya numeric) dizileriyle çalışır. Dizileri Postgres dönüştürmek için bu küçük yardımcı işlevini kullanın :jsonbint[]

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

Açıklama:

Ardından şuraya jsonb_typeof(jsonb)ulaşmak için ekleyin :

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;

İstenen sonucu tam olarak üretir.

Neden?

Açıklayan kılavuz jsonb:

Veri btreesiparişi jsonbnadiren büyük ilgi görür, ancak bütünlük için:

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

Eşit sayıda çiftli nesneler sırayla karşılaştırılır:

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

Nesne anahtarlarının depolama sırasında karşılaştırıldığını unutmayın; özellikle, daha kısa anahtarlar daha uzun anahtarlardan önce saklandığından, sezgisel olmayan sonuçlara yol açabilir, örneğin:

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

Benzer şekilde, eşit sayıda öğeye sahip diziler sırayla karşılaştırılır:

element-1, element-2 ...

Cesur vurgu benim.
Bu yüzden jsonb '[2]' < jsonb '[1, 2]'.
Ama Postgres dizileri sadece her eleman için ayrı sıralanır: '{2}'::int[] > '{1, 2}'- tam olarak aradığın şey.


0

Sonuçlarınızı json tamsayı değerlerine göre sıralamak için soruna bakın. Deneyin:

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

Sizin durumunuzda, sipariş anahtarı için bir dizi gibi görünüyor. Bu yüzden önce "anahtar" alanınızdaki değerleri birleştirmeye çalışın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.