如何从PostgreSQL json中提取数组

如何从PostgreSQL json中提取数组

作者

digoal

日期

2016-09-10

标签

PostgreSQL , json , 数组 , jsonb


背景

在PostgreSQL中使用JSON类型时,除了能存,大家更关心的是JSON中的数据的使用,例如
1. VALUE支持哪些类型,

通过以下方法可以提取JSON最外层的VALUE的数据类型

json_typeof(json)
jsonb_typeof(jsonb)

目前支持的类型如下
object, array, string, number, boolean, and null

2. 包含哪些KEY或VALUE,通过路径提取KEY或VALUE等。

3. 通过制定KEY提取VALUE,
通常通过KEY提取的VALUE还是JSON或JSONB类型,因为JSON本身就是嵌套的,但是可以通过json typeof得知它的类型。

json_typeof(json)
jsonb_typeof(jsonb)

但是SQL还是认为他是个JSON,要么就是转换为TEXT。

postgres=# create table t3(c1 jsonb);
CREATE TABLE
postgres=# insert into t3 values ('{"a":"v","b":12,"c":{"ab":"hello"},"d":12.3,"e":true,"f":[1,2,3,4],"g":["a","b"]}');
INSERT 0 1  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'a' col from t3) t;
 pg_typeof | jsonb_typeof | col
-----------+--------------+-----
 jsonb     | string       | "v"
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'b' col from t3) t;
 pg_typeof | jsonb_typeof | col
-----------+--------------+-----
 jsonb     | number       | 12
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'c' col from t3) t;
 pg_typeof | jsonb_typeof |       col
-----------+--------------+-----------------
 jsonb     | object       | {"ab": "hello"}
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'d' col from t3) t;
 pg_typeof | jsonb_typeof | col
-----------+--------------+------
 jsonb     | number       | 12.3
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'e' col from t3) t;
 pg_typeof | jsonb_typeof | col
-----------+--------------+------
 jsonb     | boolean      | true
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'f' col from t3) t;
 pg_typeof | jsonb_typeof |     col
-----------+--------------+--------------
 jsonb     | array        | [1, 2, 3, 4]
(1 row)  

postgres=# select pg_typeof(col), jsonb_typeof(col),col from (select c1->'g' col from t3) t;
 pg_typeof | jsonb_typeof |    col
-----------+--------------+------------
 jsonb     | array        | ["a", "b"]
(1 row)

4. 特定VALUE类型的处理,例如数组。

当VALUE是ARRAY时,如果需要返回ARRAY给SQL层,暂时还没有内置这样的操作符,需要自定义,本文将介绍。

如何返回JSON中存储的数组

大多数JSON操作符,返回的要么是TEXT要么是JSON.

例如以下查询
操作符->返回数组

postgres=# select pg_typeof('{"a":[1,2,3],"b":[4,5,6]}'::json->'a'), '{"a":[1,2,3],"b":[4,5,6]}'::json->'a';
 pg_typeof | ?column?
-----------+----------
 json      | [1,2,3]
(1 row)

操作符->>返回text

postgres=# select pg_typeof('{"a":[1,2,3],"b":[4,5,6]}'::json->>'a'), '{"a":[1,2,3],"b":[4,5,6]}'::json->>'a';
 pg_typeof | ?column?
-----------+----------
 text      | [1,2,3]
(1 row)

如果明确json_typeof或jsonb_typeof是array,则可以通过以下function将数组转换为行
不管是什么数组,都返回text行

json_array_elements_text(json)  

jsonb_array_elements_text(jsonb)  

postgres=# select pg_typeof(col),col from (select json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b') col) t;
 pg_typeof | col
-----------+-----
 text      | 1
 text      | 2
 text      | 3
 text      | 4
 text      | 5
 text      | 6
(6 rows)

使用数组构造器,可以将多条记录构造为数组。

postgres=# SELECT array(select json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b'));
     array
---------------
 {1,2,3,4,5,6}
(1 row)  

postgres=# SELECT pg_typeof(array(select json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b')));
 pg_typeof
-----------
 text[]
(1 row)

如何转换JSONB数组的类型

如果想构造int[],在构造前,可以将行的输出转换为对应的格式,

postgres=# SELECT array(select (json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b'))::int );
     array
---------------
 {1,2,3,4,5,6}
(1 row)  

postgres=# SELECT pg_typeof(array(select (json_array_elements_text('{"a":"B","b":[1,2,3,4,5,6]}'::json->'b'))::int ));
 pg_typeof
-----------
 integer[]
(1 row)  

编写JSON数组转换为SQL数组的函数

可以将以上方法转换为函数来使用,输入json typeof == array的json或jsonb对象,输出text数组。
转换jsonb, json array to text array

CREATE OR REPLACE FUNCTION json_arr2text_arr(_js jsonb)
   RETURNS text[] AS
$func$
SELECT ARRAY(SELECT jsonb_array_elements_text(_js))
$func$
LANGUAGE sql IMMUTABLE;  

CREATE OR REPLACE FUNCTION json_arr2text_arr(_js json)
   RETURNS text[] AS
$func$
SELECT ARRAY(SELECT json_array_elements_text(_js))
$func$
LANGUAGE sql IMMUTABLE;

转换jsonb, json array to int array

CREATE OR REPLACE FUNCTION json_arr2int_arr(_js jsonb)
   RETURNS int[] AS
$func$
SELECT ARRAY( SELECT (jsonb_array_elements_text(_js))::int )
$func$
LANGUAGE sql IMMUTABLE;  

CREATE OR REPLACE FUNCTION json_arr2int_arr(_js json)
   RETURNS int[] AS
$func$
SELECT ARRAY( SELECT (json_array_elements_text(_js))::int )
$func$
LANGUAGE sql IMMUTABLE;

例子

postgres=# select col, pg_typeof(col) from (select json_arr2text_arr(c1->'f') col from t3) t;
    col    | pg_typeof
-----------+-----------
 {1,2,3,4} | text[]
(1 row)  

postgres=# select col, pg_typeof(col) from (select json_arr2int_arr(c1->'f') col from t3) t;
    col    | pg_typeof
-----------+-----------
 {1,2,3,4} | integer[]
(1 row)  

postgres=# select col, pg_typeof(col) from (select json_arr2text_arr(c1->'g') col from t3) t;
  col  | pg_typeof
-------+-----------
 {a,b} | text[]
(1 row)

应用场景

例如业务系统在JSON中存储了一些ARRAY,这些ARRAY通常会包括一些全包含,全不包含,相交等查询,达到查询的目的。

这里就需要用到数组的包含,相交,不相干操作符来判断,那就会用到前面提到的数组的转换需求。

例子

例如JSON存储的是乐高积木的各属性。

JSON某个KEY存储的数组代表乐高积木对应型号的小零件部件号清单,然后用户需要查询哪些积木型号包含了指定零件编号,这里涉及的就是全包含的查询。

包含'a'零件

postgres=# select * from t3 where json_arr2text_arr(c1->'g') @> array['a'];
                                                 c1
-----------------------------------------------------------------------------------------------------
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}
(1 row)

同时包含'a','c'零件

postgres=# select * from t3 where json_arr2text_arr(c1->'g') @> array['a','c'];
 c1
----
(0 rows)

同时包含1,2零件

postgres=# select * from t3 where json_arr2int_arr(c1->'f') @> array[1,2];
                                                 c1
-----------------------------------------------------------------------------------------------------
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}
(1 row)

同时包含1,6零件

postgres=# select * from t3 where json_arr2int_arr(c1->'f') @> array[1,6];
 c1
----
(0 rows)

包含1或6零件

postgres=# select * from t3 where json_arr2int_arr(c1->'f') && array[1,6];
                                                 c1
-----------------------------------------------------------------------------------------------------
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}
(1 row)

即不包含1 也不包含6零件

postgres=# select * from t3 where not(json_arr2int_arr(c1->'f') && array[1,6]);
 c1
----
(0 rows)

不包含6零件

postgres=# select * from t3 where not(json_arr2int_arr(c1->'f') && array[6]);
                                                 c1
-----------------------------------------------------------------------------------------------------
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}
(1 row)

如果你不想转换为INT,那么在条件中也不要使用INT数组

postgres=# select * from t3 where not(json_arr2text_arr(c1->'f') && array['6']);
                                                 c1
-----------------------------------------------------------------------------------------------------
 {"a": "v", "b": 12, "c": {"ab": "hello"}, "d": 12.3, "e": true, "f": [1, 2, 3, 4], "g": ["a", "b"]}
(1 row)

索引

为了提升这种查询的速度,我们可以这样建立索引。

postgres=# create index idx_t3_1 on t3 using gin (json_arr2text_arr(c1->'f'));
CREATE INDEX
postgres=# set enable_seqscan=off;
SET
postgres=# explain select * from t3 where json_arr2text_arr(c1->'f') && array['1','6'];
                                  QUERY PLAN
-------------------------------------------------------------------------------
 Bitmap Heap Scan on t3  (cost=12.25..16.52 rows=1 width=32)
   Recheck Cond: (json_arr2text_arr((c1 -> 'f'::text)) && '{1,6}'::text[])
   ->  Bitmap Index Scan on idx_t3_1  (cost=0.00..12.25 rows=1 width=0)
         Index Cond: (json_arr2text_arr((c1 -> 'f'::text)) && '{1,6}'::text[])
(4 rows)

postgres=# explain select * from t3 where json_arr2text_arr(c1->'f') @> array['1','6'];
                                  QUERY PLAN
-------------------------------------------------------------------------------
 Bitmap Heap Scan on t3  (cost=12.25..16.52 rows=1 width=32)
   Recheck Cond: (json_arr2text_arr((c1 -> 'f'::text)) @> '{1,6}'::text[])
   ->  Bitmap Index Scan on idx_t3_1  (cost=0.00..12.25 rows=1 width=0)
         Index Cond: (json_arr2text_arr((c1 -> 'f'::text)) @> '{1,6}'::text[])
(4 rows)

参考

http://dba.stackexchange.com/questions/54283/how-to-turn-json-array-into-postgres-array
https://www.postgresql.org/docs/9.6/static/functions-json.html
https://www.postgresql.org/docs/9.6/static/functions-array.html

Count

时间: 2024-09-11 23:43:35

如何从PostgreSQL json中提取数组的相关文章

在PostgreSQL中使用数组时值得注意的一些地方_数据库其它

在Heap中,我们依靠PostgreSQL支撑大多数后端繁重的任务,我们存储每个事件为一个hstore blob,我们为每个跟踪的用户维护一个已完成事件的PostgreSQL数组,并将这些事件按时间排序. Hstore能够让我们以灵活的方式附加属性到事件中,而且事件数组赋予了我们强大的性能,特别是对于漏斗查询,在这些查询中我们计算不同转化渠道步骤间的输出. 在这篇文章中,我们看看那些意外接受大量输入的PostgreSQL函数,然后以高效,惯用的方式重写它. 你的第一反应可能是将PostgreSQ

ios-两个数组从第一个数组中提取值

问题描述 两个数组从第一个数组中提取值 First_mutableArray 是 1,2,3,4,5,6Second_MutableArray 是 2,4,6,8,0,12 怎么样输出这样的格式: First_mutableArray 是 1,2,3,4,5,6,8,0,12 ? 解决方案 NSMutableOrderedSet *first = [NSMutableOrderedSet orderedSetWithObjects:@"1",@"2",@"

android-转换数组中的JSON字符串为数组

问题描述 转换数组中的JSON字符串为数组 下面的字符串是作为json对象获取的: [ { "id": "picture1", "caption": "sample caption", "picname": "sample picture name" } ] 然后将它转换到数组中,这样可以填充到列表中. JSONArray myjsonarray = myjson.toJSONArray

java 7-求第m个到第n个素数之间的素数和,求帮忙看下哪里错了 提取数组求和的时候总是在数组中出现0

问题描述 求第m个到第n个素数之间的素数和,求帮忙看下哪里错了 提取数组求和的时候总是在数组中出现0 public class All { public static void main(String[] args) { int a[] = new int[200]; //将前200个数中的素数提取出来放入数组a中 for(int i = 1 ; i < 200 ; i ++){ boolean isPrime = true; for(int k = 2 ; k < i ; k ++){ if

在PHP语言中使用JSON和将json还原成数组的方法_php实例

在之前我写过php返回json数据简单实例,刚刚上网,突然发现一篇文章,也是介绍json的,还挺详细,值得参考.内容如下 从5.2版本开始,PHP原生提供json_encode()和json_decode()函数,前者用于编码,后者用于解码. 一.json_encode() <?php $arr = array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5); echo json_encode($arr); ?> 输出 {"a&

c++-C++可以用指针数组从字符串中提取子字符串么?

问题描述 C++可以用指针数组从字符串中提取子字符串么? C++可以用指针数组从字符串中提取子字符串么?如果可以请给一个示范QAQ 解决方案 http://www.cnblogs.com/xiangzi888/archive/2012/04/16/2451947.html /* strtok example */#include <stdio.h>#include <string.h>int main (void){ char str[] = ""- This

php录入页面中动态从数据库中提取数据的实现

动态|数据|数据库|页面 摘要:用php制作动态web页面时,在提交服务器之前,让php根据用户在当前页面上录入的某字段的值立即从数据库中取出相关的其它字段的值并显示到当前页面上,是php程序开发中的难点.本文以一个具体实例详细介绍了怎样将两个html内嵌式语言php和javascript巧妙结合起来,解决这个难点的具体方法. 关键词:php.动态.html. 现在的网站已经从以前提供静态信息的形式发展到交互式的提供动态信息业务的方式.web的信息服务形式可以概括为两点:向客户提供信息:记录客户

从MP3中提取歌曲信息(C#)

从MP3中提取歌曲信息 一首MP3歌曲除了音乐信息外,还包含了如歌名.演唱者等信息,当我们用winamp软件听音乐时,播放清单就自动将这些信息读出来.大部分人都喜欢从网上下载音乐,但下载下来的MP3文件名都是文件上传系统自动取名的,和歌曲本身根本不相符,所以,给用户带来了很大的麻烦.但是,懒人有懒人的做法,我们何不自己写一个程序,将歌曲信息自动读出来并为MP3文件自动更名呢? 下面我就以C#为工具,把开发过程写出来. 一首MP3的额外信息存放在文件的最后面,共占128个字节,其中包括以下的内容(

PHP函数实现从一个文本字符串中提取关键字的方法

  本文实例讲述了PHP函数实现从一个文本字符串中提取关键字的方法.分享给大家供大家参考.具体分析如下: 这是一个函数定位接收一个字符串作为参数(连同其他配置可选参数),并且定位该字符串中的所有关键字(出现最多的词),返回一个数组或一个字符串由逗号分隔的关键字.功能正常工作,但我正在改进,因此,感兴趣的朋友可以提出改进意见. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31