web-dev-qa-db-ja.com

postgres 9.3でjson配列をpostgres int配列に変換する方法

Json配列をpostgres int配列に変換し、その結果をクエリする必要があるシナリオがあります。以下は私の配列です

      ID            DATA
       1           {"bookIds" : [1,2,3,5], "storeIds": [2,3]} 
       2           {"bookIds" : [4,5,6,7], "storeIds": [1,3]}
       3           {"bookIds" : [11,12,10,9], "storeIds": [4,3]}

BooksId配列をint配列に変換して、後でクエリしたいのですが。 postgres 9.3では可能ですか? 9.4 +はより多くのJSONサポートを提供していますが、現時点ではデータベースを更新できません。

以下のクエリは私にエラーを与えます

  Select data::json->>'bookIds' :: int[] from table

 ERROR:  malformed array literal: "bookIds"
 LINE 1: Select data::json->>'bookIds' :: int[] from table

Postgres 9.3でjson配列内の要素をクエリすることは可能ですか?事前に感謝します...

8
Max Maddy

問題の設定は次のようになります。

_create table a_table (id int, data json);
insert into a_table values
(1, '{"bookIds": [1,2,3,5], "storeIds": [2,3]}'), 
(2, '{"bookIds": [4,5,6,7], "storeIds": [1,3]}'),
(3, '{"bookIds": [11,12,10,9], "storeIds": [4,3]}');
_

Json値の適切な構文に注意してください。

関数 json_array_elements() を使用できます

_select id, array_agg(e::text::int)
from a_table, json_array_elements(data->'bookIds') e
group by 1
order by 1;

 id |  array_agg   
----+--------------
  1 | {1,2,3,5}
  2 | {4,5,6,7}
  3 | {11,12,10,9}
(3 rows)    
_

any() を使用して、配列内の要素を検索します。例:

_select *
from (
    select id, array_agg(e::text::int) arr
    from a_table, json_array_elements(data->'bookIds') e
    group by 1
    ) s
where 
    1 = any(arr) or
    11 = any(arr);

 id |     arr      
----+--------------
  1 | {1,2,3,5}
  3 | {11,12,10,9}
(2 rows)
_

_<@ operator_ についてもお読みください。

また、要素を調べることにより、json配列を(int配列に変換せずに)検索することもできます。例:

_select t.*
from a_table t, json_array_elements(data->'bookIds') e
where e::text::int in (1, 11);

 id |                     data                      
----+-----------------------------------------------
  1 | {"bookIds" : [1,2,3,5], "storeIds": [2,3]}
  3 | {"bookIds" : [11,12,10,9], "storeIds": [4,3]}
(2 rows)
_
12
klin

これらの2つの関数(json/jsonb用)は 素晴らしい答え から この質問 に完全に変更されました

CREATE OR REPLACE FUNCTION json_array_castint(json) RETURNS int[] AS $f$
    SELECT array_agg(x)::int[] || ARRAY[]::int[] FROM json_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION jsonb_array_castint(jsonb) RETURNS int[] AS $f$
    SELECT array_agg(x)::int[] || ARRAY[]::int[] FROM jsonb_array_elements_text($1) t(x);
$f$ LANGUAGE sql IMMUTABLE;

次のように使用できます。

SELECT json_array_castint('[1,2,3]')

期待されるリターンを提供します{1,2,3}のようにinteger[]SELECTステートメントのそれぞれで空の配列と連結している理由がわからない場合は、空のjson/jsonb配列をinteger[]空の配列(期待どおり)ではなく、戻り値はありません(望ましくありません)。上記の方法で行うと

SELECT json_array_castint('[]')

{}の代わりに。私がそれを追加した理由の詳細については こちら を参照してください。

4
Joel B

私は少し簡単に行きます:

select * from
(
select t.id, value::text::int as bookvalue
  from testjson t, json_array_elements(t.data->'bookIds')
) as t
where bookvalue in (1,11)

ここでそれが機能するのを見てください: http://sqlfiddle.com/#!15/e69aa/37

3
Jorge Campos