2015-07-24 3 views
6

У меня есть определенная таблица:PostgreSQL JSONB типов запросов по каждой клавише

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 

, что дало бы someth ING, как:

a | 2 
b | 2 
c | 2 
d | 2 
e | 1 
f | 1 
+1

Ваш 'оператор INSERT' не отформатирована совсем верно. – Travis

+1

Функция ['json [b] _typeof (json [b])'] (http://www.postgresql.org/docs/current/static/functions-json.html) дает точно, что вам нужно (требуется PostreSQL 9.4+). Но я не уверен, как вы хотите объединить свои результаты, f.ex. как вы хотите представить 'd | boolean: 1 строка: 1' строка? – pozs

+1

Это решение. Как только я нашел одну функцию 'typeof', я не думал искать вторую. – Travis

ответ

4

EDIT:

Как 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 primitive types, и выход, кажется однозначным. Так что этот запрос будет делать то, что Вы желаете:

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) 
+0

удивительный ответ, очень полезно, спасибо! – Alex

Смежные вопросы