PostgreSQL - counting the elements in the JSON - arrays

I have a JSON type column called "log_data" and the data stored in it is in the format [{"key":"test123123","identity":"user#test.it","identity_type":"email"}].
I want to count how many records for a given value for a given key in json:
Doesn't work
SELECT count (distinct esas_logs.log_id) AS "count" FROM "esas_logs" WHERE log_data->0->>'identity' = 'user#test.it'
[2016-06-30 13:59:18] [42883] ERROR: operator does not exist: json = unknown
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.

use json_array_length()
test=# select json_array_length('[{"key":"test123123","identity":"user#test.it","identity_type":"email"}]');
json_array_length
-------------------
1
(1 row)

According to the doc, you should use the ? operator.
If your column type is JSON:
SELECT COUNT(esas_logs ? 'log_id') FROM esas_logs WHERE ...
If you column is a TEXT or VARCHAR:
SELECT COUNT(esas_logs::jsonb ? 'log_id') FROM esas_logs WHERE ...

Related

Extracting elements from a varchar column in snowflake

I have a sample data, as shown below;
NAME
Values
Typeof(Values)
BNL
[1,2]
VARCHAR
As seen the data type is VARCHAR for the second column.
Expected Output
Name
Values
BNL
1
BNL
2
In a way, we want to split the row into two rows depending on how many elements we have in the Values column. I was looking into FLATTEN as an option;
select temp.*,
t.value
from temp,
table(flatten(temp.values)) as t;
But since it is a VARCHAR, we get following error message;
invalid type [VARCHAR(16777216)] for parameter '1'
Can I please get some help here?thanx
One way is to use TRY_PARSE_JSON:
select temp.*,
t.value
from temp,
table(flatten(TRY_PARSE_JSON(temp.values))) as t;

How to parse a table with a JSON array field in PostgreSQL into rows?

I have a table that contains a json array. Here is a sample of the contents of the field from:
SELECT json_array FROM table LIMIT 5;
Result:
[{"key1":"value1"}, {"key1":"value2"}, ..., {"key2":"value3"}]
[]
[]
[]{"key1":"value1"}
[]
How can I retrieve all the values and count how many of each value was found?
I am using PostgreSQL 9.5.14, and I have tried the solutions here Querying a JSON array of objects in Postgres
and the ones suggested to me by another generous stackoverflow user in my last question: How can I parse JSON arrays in postgresql?
I tried:
SELECT
value -> 'key1'
FROM
table,
json_array_elements(json_array);
which sadly does not work for me due to receiving the error: cannot call json_array_elements on a scalar
This error happens when using a query that returns more than one row or more than one column as a scalar subquery.
Another solution I tried was:
SELECT json_array as json, (json_array->0),
coalesce(
case
when (json_array->0) IS NULL then null
else (json_array->0->>'key1')
end,
'No value') AS "Value"
FROM table;
which only returned null values for the "Value"
Referencing Querying a JSON array of objects in Postgres I attempted to use this solution as well:
WITH json_test (col) AS (
values (json_arrays)
)
SELECT
y.x->'key1' "key1"
FROM json_test jt,
LATERAL (SELECT json_array_elements(jt.col) x) y;
But I would need to be able to fit all the elements of the json_arrays into json_test
So far I have only attempted to list all the values in the all json arrays, but my ideal end-result for the query resembles this:
Value | Amount
---------------
value1 | 48
value2 | 112
value3 | 93
value4 | 0
Yet again I am grateful for any help with this, thank you in advance.
step-by-step demo:db<>fiddle
SELECT
each.value,
COUNT(*)
FROM
data,
json_array_elements(json_array) elems, -- 1
json_each_text(elems) each -- 2
GROUP BY each.value -- 3
Expand array into one row for each array element
split the key/value pairs into two columns
group by the new value column/count

How to use LIKE on elements of a JSONB array?

I need to search with LIKE or ILIKE - applied to elements of a JSONB[] column.
I can use unnest() to display nested JSONB elements separately, but I am having trouble combining that with my LIKE expression. My query:
SELECT
UNNEST( column_jsonb[] )
FROM
table1
WHERE
UNNEST( column_jsonb[] ) ->> 'member_type' LIKE '%member%'
Results in an error:
argument of WHERE must not return a set
How to get this right?
If it's indeed a jsonb[] column:
SELECT * -- or whatever
FROM t, unnest(jsonb_col) j
WHERE j->>'member_type' LIKE '%member%';
That's an implicit CROSS JOIN LATERAL.
If it's a JSON array in a plain jsonb column (more likely):
SELECT *
FROM t1, jsonb_array_elements(jsonb_col) j
WHERE j->>'member_type' LIKE '%member%';
Related:
Query for array elements inside JSON type

Access the index of an element in a jsonb array

I would like to access the index of an element in a jsonb array, like this:
SELECT
jsonb_array_elements(data->'Steps') AS Step,
INDEX_OF_STEP
FROM my_process
I don't see any function in the manual for this.
Is this somehow possible?
Use with ordinality. You have to call the function in the from clause to do this:
with my_process(data) as (
values
('{"Steps": ["first", "second"]}'::jsonb)
)
select value as step, ordinality- 1 as index
from my_process
cross join jsonb_array_elements(data->'Steps') with ordinality
step | index
----------+-------
"first" | 0
"second" | 1
(2 rows)
Read in the documentation (7.2.1.4. Table Functions):
If the WITH ORDINALITY clause is specified, an additional column of type bigint will be added to the function result columns. This column numbers the rows of the function result set, starting from 1.
You could try using
jsonb_each_text(jsonb)
which should supply both the key and value.
There is an example in this question:
Extract key, value from json objects in Postgres
except you would use the jsonb version.

postgres comparing varying character with array from string_to_array

I'm having problems comparing Postgres types, and would be grateful for some help. I am extracting valid document types from a configuration table that holds a tilda-separated string, as follows:
SELECT string_to_array(value,'|') as document_kinds
FROM company_configs
WHERE option = 'document_kinds'
this gives me an array of values, so
'doc1|doc2|doc3' becomes {doc1,doc2,doc3}
Next I need to select the documents for a given person which match my document types:
SELECT * FROM people
JOIN documents ON ...
WHERE kind IN
(SELECT string_to_array(value,'|') as document_kinds
FROM company_configs
WHERE option = 'document_kinds')
the documents.kind column is 'character varying'
my understanding is that string_to_array is producing an array of text values 'text[]'
This query produces the error 'ERROR: operator does not exist: character varying = text[]'
If I cast 'kind' into text, with
SELECT * FROM people
JOIN documents ON ...
WHERE kind::text IN
(SELECT string_to_array(value,'|') as visa_document_kinds FROM languages_united.company_configs WHERE option = 'visa_document_kinds')
I get the error 'ERROR: operator does not exist: text = text[]'
I'm not sure how to compare the two, and would be grateful for any advice.
Thanks in advance
Dan
Postgres 9.4.1
You can select against any array element by using the ANY operator, if your sub-query returns exactly one row:
SELECT *
FROM people
JOIN documents ON ...
WHERE kind = ANY (
SELECT string_to_array(value,'|') as document_kinds
FROM company_configs
WHERE option = 'document_kinds');
If the sub-query possibly returns multiple rows, you can use the regexp_split_to_table() function:
SELECT *
FROM people
JOIN documents ON ...
JOIN (
SELECT document_kinds
FROM company_configs,
regexp_split_to_table(value, '\|') as document_kinds
WHERE option = 'document_kinds') sub ON sub.document_kinds = kind;
(You will have to tweak this to match the rest of your query.)

Resources