web-dev-qa-db-ja.com

配列を含むjsonbキーのソート順をカスタマイズする

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

それを達成する方法はありますか?

9
Antonio

まず、質問と列名_"key"_は誤解を招く可能性があります。列キーには、JSONkeysは含まれず、valuesのみが含まれます。それ以外の場合は、関数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 ...
_

大胆な強調鉱山。
それが_jsonb '[2]' < jsonb '[1, 2]'_です。
しかし、Postgres配列は要素ごとにソートするだけです:_'{2}'::int[] > '{1, 2}'_-まさにあなたが探していたものです。

8

問題を参照して、json整数値で結果を並べ替えます。試してください:

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

あなたの場合、それは順序付けキーの配列のようです。したがって、最初に「キー」フィールドの値を連結してみてください。

0
dlg_