2015-07-24 41 views
6

mam pewną tabelę:PostgreSQL JSONB typy zapytań z poszczególnych klawiszy

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]}'); 

Jak kwerendy typy każdego klawisza w tej tabeli, więc byłoby dać coś wyjściowy takiego:

a | string:2 
b | number:2 
c | null:2 
d | boolean:1 string:1 
e | string:1 
f | jsonb:1 -- or anything 

Wiem tylko, jak zdobyć klucze i policzyć, ale nie wiem, jak uzyskać typ każdego klucza:

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

który dałby coś ing jak:

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

Twój 'oświadczenie INSERT' nie jest sformatowana rację. – Travis

+1

Funkcje ['json [b] _typeof (json [b])'] (http://www.postgresql.org/docs/current/static/functions-json.html) dają dokładnie to, czego potrzebujesz (wymaga PostreSQL 9.4+). Ale nie jestem pewien, jak chcesz zebrać wyniki, np. jak chcesz reprezentować 'd | boolean: 1 ciąg: 1 wiersz? – pozs

+1

To jest rozwiązanie. Kiedy znalazłem jedną funkcję 'typeof', nie myślałem, że będę szukał sekundy. – Travis

Odpowiedz

4

EDIT:

Jak pozs zaznacza, istnieją dwa typeof funkcje: jeden dla JSON i jeden dla SQL. To zapytanie jest jednym szukasz:

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; 

Old Odpowiedź: (Hej, to działa ...)

To zapytanie zwróci typ klawiszy:

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

... niestety zauważysz, że Postgres nie rozróżnia różnych typów JSON. to chodzi o to wszystko jak jsonb, więc wyniki są następujące:

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) 

Jednak nie jest to, że wiele JSON primitive types, a wyjście wydaje się być jednoznaczna. Więc ta kwerenda będzie robić to, czego chce:

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; 

wyjściowa:

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

niesamowita odpowiedź, bardzo pomocne, dzięki! – Alex