2015-07-24 13 views
6

ho certo tabella:PostgreSQL JSONB tipi di query di ogni chiavi

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

come interrogare i tipi di ogni tasto in tale tabella, quindi sarebbe dare qualcosa di output come questo:

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

so solo il modo per ottenere le chiavi e contare, ma non so come ottenere il tipo di ciascun tasto:

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

che darebbe someth Ing come:

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

vostro 'dichiarazione INSERT' non è formattato giusto. – Travis

+1

Le funzioni ['json [b] _typeof (json [b])'] (http://www.postgresql.org/docs/current/static/functions-json.html) forniscono esattamente ciò di cui hai bisogno (Richiede PostreSQL 9.4+). Ma non sono sicuro, come si desidera aggregare i risultati, ad es. come vuoi rappresentare il 'd | booleano: 1 stringa: 1' riga? – pozs

+1

Questa è la soluzione. Una volta ho trovato una funzione 'typeof', non ho pensato di andare a cercare un secondo. – Travis

risposta

4

EDIT:

Come pozs sottolinea, ci sono due typeof funzioni: uno per JSON e uno per SQL. Questa query è quello che stai cercando:

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 Risposta: (Hey, funziona ...)

Questa query restituirà il tipo di chiavi:

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

... sfortunatamente, noterai che Postgres non distingue tra i diversi tipi JSON. riguarda tutto come jsonb, quindi i risultati sono:

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) 

Tuttavia, non ci sono che molti JSON primitive types, e l'uscita sembra essere ambiguo. Così questa query farà quello che hai intenzione:

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; 

uscita:

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

risposta fantastica, molto utile, grazie! – Alex