PostgreSQL JSONB查询各个键的类型

7

我有一张表:

CREATE TABLE x(
  id BIGSERIAL PRIMARY KEY,
  data JSONB 
);
INSERT INTO x(data) 
VALUES( '{"a":"test", "b":123, "c":null, "d":true}' ),
      ( '{"a":"test", "b":123, "c":null, "d":"yay", "e":"foo", "f":[1,2,3]}' );

如何查询表中每个键的类型,使其输出类似于以下内容:
a | string:2 
b | number:2
c | null:2
d | boolean:1 string:1
e | string:1 
f | jsonb:1 -- or anything

我只知道如何获取键和计数,但不知道如何获取每个键的类型:

SELECT jsonb_object_keys(data), COUNT(id) FROM x GROUP BY 1 ORDER BY 1

这将会得到类似于以下内容:
a |  2
b |  2
c |  2
d |  2
e |  1
f |  1

1
你的INSERT语句格式不太对。 - Travis
1
json[b]_typeof(json[b]) 函数可以准确地提供您所需的内容(需要 PostreSQL 9.4+)。但我不确定您想要如何汇总结果,例如,您想如何表示 d | boolean:1 string:1 行? - pozs
1
这就是解决方案。一旦我找到了一个 typeof 函数,我就没有想过去寻找第二个。 - Travis
jsonb_typeof比以前快了约10%,感谢大家。 - Kokizzu
2个回答

7

编辑:

正如pozs所指出的那样,typeof函数有两个版本:一个用于JSON,一个用于SQL。这是你要找的查询:

SELECT
    json_data.key,
    jsonb_typeof(json_data.value),
    count(*)
FROM x, jsonb_each(x.data) AS json_data
group by key, jsonb_typeof
order by key, jsonb_typeof;

旧回答:(嘿,它起作用了...)

此查询将返回密钥的类型:

SELECT
    json_data.key,
    pg_typeof(json_data.value),
    json_data.value
FROM x, jsonb_each(x.data) AS json_data;

很遗憾,您会发现Postgres不区分不同的JSON类型。它将所有内容视为jsonb,因此结果如下:

 key1 | value1 |   value   
------+--------+-----------
 a    | jsonb  | "test"
 b    | jsonb  | 123
 c    | jsonb  | null
 d    | jsonb  | true
 a    | jsonb  | "test"
 b    | jsonb  | 123
 c    | jsonb  | null
 d    | jsonb  | "yay"
 e    | jsonb  | "foo"
 f    | jsonb  | [1, 2, 3]
(10 rows)

然而,JSON基本类型并不多,输出结果似乎是清晰明了的。因此,以下查询会达到您的目的:
with jsontypes as (
    SELECT
        json_data.key AS key1,
        CASE WHEN left(json_data.value::text,1) = '"'  THEN 'String'
             WHEN json_data.value::text ~ '^-?\d' THEN
                CASE WHEN json_data.value::text ~ '\.' THEN 'Number'
                     ELSE 'Integer'
                END
             WHEN left(json_data.value::text,1) = '['  THEN 'Array'
             WHEN left(json_data.value::text,1) = '{'  THEN 'Object'
             WHEN json_data.value::text in ('true', 'false')  THEN 'Boolean'
             WHEN json_data.value::text = 'null'  THEN 'Null'
             ELSE 'Beats Me'
        END as jsontype
    FROM x, jsonb_each(x.data) AS json_data -- Note that it won't work if we use jsonb_each_text here because the strings won't have quotes around them, etc.
)
select *, count(*) from jsontypes
group by key1, jsontype
order by key1, jsontype;

输出:

 key1 | jsontype | count 
------+----------+-------
 a    | String   |     2
 b    | Integer  |     2
 c    | Null     |     2
 d    | Boolean  |     1
 d    | String   |     1
 e    | String   |     1
 f    | Array    |     1
(7 rows)

1

你可以使用jsonb_typeof来改进你的上一个查询

with jsontypes as (
    SELECT
        json_data.key AS key1,
        jsonb_typeof(json_data.value) as jsontype
    FROM x, jsonb_each(x.data) AS json_data
)
select *, count(*)
from jsontypes
group by 1, 2
order by 1, 2;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接