Passen Sie die Sortierreihenfolge für jsonb-Schlüssel mit Arrays an


9

Ich habe eine Tabelle in PostgreSQL mit einigen Daten:

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

Und ich versuche diese Zeilen so zu sortieren:

SELECT key FROM t2 order by key;

Das Ergebnis ist:

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

Aber was ich brauche ist:

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

Gibt es einen Weg, dies zu erreichen?


Hast du hier deine Antwort?
Erwin Brandstetter

Antworten:


8

Zunächst einmal sind Ihre Frage sowie Ihr Spaltenname "key"irreführend. Der Spaltenschlüssel enthält keine JSON- Schlüssel , nur Werte . Sonst könnten wir die Funktion verwenden jsonb_object_keys(jsonb), um Schlüssel zu extrahieren, aber das ist nicht so.

Angenommen, alle Ihre JSON-Arrays sind entweder leer oder enthalten ganzzahlige Zahlen, wie gezeigt. Und die Skalarwerte (Nicht-Arrays) sind ebenfalls ganzzahlig.

Ihre grundlegende Sortierreihenfolge würde mit Postgres integer(oder numeric) Arrays funktionieren . Ich benutze diese kleine Hilfsfunktion , um jsonbArrays in Postgres zu konvertieren 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)';

Erläuterung:

Fügen Sie dann hinzu jsonb_typeof(jsonb), um zu folgendem Ergebnis zu gelangen:

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;

Erzeugt genau das gewünschte Ergebnis.

Warum?

Das Handbuch für jsonberklärt:

Die btreeBestellung von jsonbBezugspunkten ist selten von großem Interesse, der Vollständigkeit halber jedoch:

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

Objekte mit gleicher Anzahl von Paaren werden in der folgenden Reihenfolge verglichen:

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

Beachten Sie, dass Objektschlüssel in ihrer Speicherreihenfolge verglichen werden. Insbesondere da kürzere Schlüssel vor längeren Schlüsseln gespeichert werden, kann dies zu Ergebnissen führen, die möglicherweise nicht intuitiv sind, wie z.

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

In ähnlicher Weise werden Arrays mit der gleichen Anzahl von Elementen in der folgenden Reihenfolge verglichen:

element-1, element-2 ...

Meine kühne Betonung.
Deshalb jsonb '[2]' < jsonb '[1, 2]'.
Aber Postgres-Arrays sortieren nur Element für Element: '{2}'::int[] > '{1, 2}'- genau das, wonach Sie gesucht haben.


0

Beziehen Sie sich auf das Problem, um Ihre Ergebnisse nach json-Ganzzahlwerten zu ordnen. Versuchen:

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

In Ihrem Fall scheint es sich um ein Array für den Bestellschlüssel zu handeln. Versuchen Sie also zuerst, die Werte in Ihrem "Schlüsselfeld" zu verknüpfen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.