I have a table that looks like this:
id
attrs
1
{"a":{"kind":"kind_1", "value":"val_1"}, "b":{"kind":"kind_2", "value":"val_2"}
2
{"c":{"kind":"kind_3", "value":"val_1"}}
3
{"a":{"kind":"kind_1", "value":"val_1"}, "d":{"kind":"kind_4", "value":"val_4"}, .....
I would like to extract all the unique value, so the output would be:
val_1
val_2
val_4
...
I tried to use jsonb_each method for it, but without any luck
You can use a JSON Path query:
select distinct v.item #>> '{}'
from the_table t
cross join jsonb_array_elements(jsonb_path_query_array(t.attrs, '$.**.value')) as v(item);
The v.item #>> '{}' is a trick to convert a scalar JSON value to text (because casting it wouldn't work)
Alternatively you can use jsonb_each() twice:
select distinct v.value
from the_table t
cross join jsonb_each(t.attrs) as i(key, item)
cross join jsonb_each_text(i.item) as v(key, value)
where v.key = 'value'
Related
How do I select only "A" named values from a postgresql database table.
Id
Column
1001
{"results":[{"name":"A","value":"7.8"}, {"name":"B","value":"0.5"}]}
1002
{"results":[{"name":"B","value":"5.4"}, {"name":"D","value":"4.5"}]}
1003
{"results":[{"name":"D","value":"4.8"}, {"name":"A","value":"6.7"}]}
Results should be as
ID
Name
Value
1001
A
7.8
1003
A
6.7
You can use a JSON path query to access such an element:
select id,
'A' as name
jsonb_path_query_first("column", '$.results[*] ? (#.name == "A").value') #>> '{}' as value
from the_table;
This assumes that column (which is a horrible name) is defined as jsonb (which it should be). If it's not, you need to cast it "column"::jsonb
jsonb_path_query_first returns a jsonb value and there is no straighforward way to convert that to a proper text value (as e.g. ->> does). The #>> '{}' is a little hack to convert a scalar jsonb value to text.
According to column type you can use json_to_recordset (If type of column is json) or jsonb_to_recordset (If type of column is jsonb)
Demo
JSONB sample
select
t.id,
x.name,
x.value
from
test t
cross join jsonb_to_recordset(("column"::jsonb) -> 'results') as x(name text, value text)
where
x.name = 'A'
JSON sample
select
t.id,
x.name,
x.value
from
test t
cross join json_to_recordset(("column"::json) -> 'results') as x(name text, value text)
where
x.name = 'A'
I have two instances of the type integer[] (generated by the Timescale histogram function), e.g. {3,5,1} and {2,2,2}.
I would like to add these two Arrays to {5,7,3} but using
SELECT "ID", histogram(...) + histogram(...)
FROM "ID"
GROUP BY "ID"
throws the following error: operator does not exist: integer[] + integer[]. Is there any way to accomplish this?
I don't think there is such a function.
In order to achieve your goal (in SQL) you'd have to unnest the arrays, then add the corresponding elements and aggregate the results back to array.
SELECT
array_agg(
COALESCE(h1.val, 0)+COALESCE(h2.val, 0)
ORDER BY COALESCE(h1.row_number, h2.row_number)
) as result
FROM
(SELECT ROW_NUMBER() over (), val FROM unnest('{3,5,1,5}'::int[]) as val) as h1
FULL JOIN (SELECT ROW_NUMBER() over (), val FROM unnest('{2,2,2}'::int[]) as val) as h2 ON h1.row_number=h2.row_number
I'm using ROW_NUMBER window function to get the array element number.
FULL JOIN is required because the arrays may be of different length. It is also the reason why COALESCE is required when adding the elements.
Thanks to #a_horse_with_no_name the query may be rewritten using ordinality without relying on row_number() function:
SELECT
array_agg(
COALESCE(h1.val, 0)+COALESCE(h2.val, 0)
ORDER BY COALESCE(h1.no, h2.no)
) as result
FROM
unnest('{3,5,1,5}'::int[]) WITH ORDINALITY as h1(val, no)
FULL JOIN unnest('{2,2,2}'::int[]) WITH ORDINALITY as h2(val, no) ON h1.no=h2.no
I have a details table with adeet column defined as jsonb[]
a sample value stored in adeet column is as below image
Sample data stored in DB :
I want to return the rows which satisfies id=26088 i.e row 1 and 3
I have tried array operations and json operations but it does'nt work as required. Any pointers
Obviously the type of the column adeet is not of type JSON/JSONB, but maybe VARCHAR and we should fix the format so as to convert into a JSONB type. I used replace() and r/ltrim() funcitons for this conversion, and preferred to derive an array in order to use jsonb_array_elements() function :
WITH t(jobid,adeet) AS
(
SELECT jobid, replace(replace(replace(adeet,'\',''),'"{','{'),'}"','}')
FROM tab
), t2 AS
(
SELECT jobid, ('['||rtrim(ltrim(adeet,'{'), '}')||']')::jsonb as adeet
FROM t
)
SELECT t.*
FROM t2 t
CROSS JOIN jsonb_array_elements(adeet) j
WHERE (j.value ->> 'id')::int = 26088
Demo
You want to combine JSONB's <# operator with the generic-array ANY construct.
select * from foobar where '{"id":26088}' <# ANY (adeet);
I have two jsonb fields in the table below and I would like to do a query where I filter any key of the dictionary.
My problem is that those dictionaries are inside of a list and when I try to access them with:
SELECT *
FROM public.monitoring_environmentalcontrol
WHERE celery_status->'queue'='0'
I get nothing:
You can use jsonb_array_elements DOC function to achieve your goal plus a LATERAL JOIN 7.2.1.5. LATERAL Subqueries on it:
This is the setup I created:
create table test (
id int,
celery_status jsonb
);
insert into test values
(1,'[{"queue":"a"}, {"queue":"b"}, {"queue":"c"}]'),
(2,'[{"queue":"d"}, {"queue":"e"}, {"queue":"f"}]'),
(3,'[{"queue":"g"}, {"queue":"h"}, {"queue":"i"}]');
This is the query:
select t.id, t.celery_status, obj->>'queue'
from test t
join lateral
jsonb_array_elements(t.celery_status) obj(value) on obj->>'queue' = 'a'
You can see it working here: http://sqlfiddle.com/#!17/bf7bf/6
I am trying to rename a json key of all the objects in a list e.g. given my_table with my_col containing a jsonb list:
[{name:0}, {name:1}, {name:2}]
I have worked out how to change a single element of a list by removing and adding a key using explicit indexing e.g.
select (my_col->0)::jsonb - 'name' ||
jsonb_build_object('new_name', my_col->0->'name')
from my_table
But how can this then be applied to all elements in the list?
Here is my best answer so far that works using a lateral join.
update my_table t1
set my_col =
(select json_agg(el::jsonb - 'name' || jsonb_build_object('new_name', el->'name'))
from my_table t2, jsonb_array_elements(t2.my_col) as el
where t1.id = t2.id)
Ideally there would just be some neat pattern matching operators e.g. my_col->*->'name'.