extract all values of postgresql jsonb object - postgresql

i have a postgresql table t1 , id integer , data jsonb
id | data
--------------------
1 | {"1":{"11":11},"2":{"12":12}}
and i need a function to extract all key/value in separate rows
like this
key | values
----------------------
1 | {"11":11}
2 | {"12":12}
in "hstore" dataType , there was "hvals" function , do this
but in jsonb i dont find similar function

You are looking for jsonb_each
with t1 (id, data) as (
values (1, '{"1":{"11":11},"2":{"12":12}}'::jsonb)
)
select t.*
from t1, jsonb_each(data) as t(k,v)
returns:
k | v
--+-----------
1 | {"11": 11}
2 | {"12": 12}

Related

Why is my equal not working on 2 identical String

I'm using postgresql 13 and I'm trying to fetch data from a table based on one of its column.
Said table is defined as follow :
create table my_table (
my_table_id int8 not null,
value varchar(255) not null,
another_table_id int8 not null,
primary key (my_table_id) );
create index my_table__lower_value__idx
ON my_table USING btree (lower((value)::text));
Now, when I'm running both query :
first to select a row with a where clause based on a value defined in another table (column my_table_id)
second to select the same row and the same table based on a value defined in this table (column value).
Second query is not returning any row.
See below :
db > select * from my_table where my_table_id = 1001;
my_table_id | value | another_table_id
------------+--------+-----------------
1 | value1 | 1001
(1 row)
db > select * from my_table where lower(value) = lower('value1');
my_table_id | value | another_table_id
------------+--------+-----------------
(0 rows)
Mind you, if I ran this query with some other values, it works :
db > select * from my_table where my_table_id = 1002;
my_table_id | value | another_table_id
------------+--------+-----------------
2 | value2 | 1002
(1 row)
db > select * from my_table where lower(value) = lower('value2');
my_table_id | value | another_table_id
------------+---------+-----------------
2 | value2 | 1002
(1 row)
Why this difference ?
What I've tried so far :
using select * from my_table where value in (select value from my_table where another_table_id = 1001); does not work
using lower on each part of equal statement: still not working on first case.
using LIKE keyword : it works fine in both cases

how to create type in postgres (array) type using custom type

I have custom types in oracle and then I need to populate the same in Postgres.
This oracle type creation code
CREATE OR REPLACE TYPE vr_return_attendee_rp AS OBJECT (
requestid NUMBER,
startdate VARCHAR2(50),
CONSTRUCTOR FUNCTION vr_return_attendee_rp RETURN SELF AS RESULT
);
/
CREATE OR REPLACE TYPE BODY "VR_RETURN_ATTENDEE_RP" AS
CONSTRUCTOR FUNCTION vr_return_attendee_rp RETURN SELF AS RESULT AS
BEGIN
self.requestid := NULL;
self.visitdate := NULL;
return;
END;
END;
/
CREATE OR REPLACE TYPE "VR_RETURN_ATTENDEE_ARR" AS
VARRAY(10000) OF vr_return_attendee_rp;
And then I created type in Postgres like the following
CREATE TYPE vr_return_attendee_rp AS (
requestid INT,
startdate VARCHAR(50)
);
How to create "VR_RETURN_ATTENDEE_ARR" type in Postgres.
PostgreSQL has native support for array types as well as functions and operators to manipulate them.
create type vr_return_attendee_rp as (request_id int, startdate varchar(50));
CREATE TYPE
create table use_vr_type(id serial primary key, vrdata vr_return_attendee_rp[]);
CREATE TABLE
insert into use_vr_type (vrdata) values (array['(1, "2020-01-01")', '(2, "2020-02-01")']::vr_return_attendee_rp[]);
INSERT 0 1
select * from use_vr_type;
id | vrdata
----+-----------------------------------------------
1 | {"(1,\" 2020-01-01\")","(2,\" 2020-02-01\")"}
(1 row)
select id, vrdata[1].request_id, vrdata[1].startdate from use_vr_type;
id | request_id | startdate
----+------------+-------------
1 | 1 | 2020-01-01
(1 row)
select id, unnest(vrdata) from use_vr_type;
id | unnest
----+-------------------
1 | (1," 2020-01-01")
1 | (2," 2020-02-01")
(2 rows)
select id, a.*
from use_vr_type
cross join lateral unnest(vrdata) with ordinality as a(request_id, startdate, rownum);
id | request_id | startdate | rownum
----+------------+-------------+--------
1 | 1 | 2020-01-01 | 1
1 | 2 | 2020-02-01 | 2
(2 rows)

Maintaining order in DB2 "IN" query

This question is based on this one. I'm looking for a solution to that question that works in DB2. Here is the original question:
I have the following table
DROP TABLE IF EXISTS `test`.`foo`;
CREATE TABLE `test`.`foo` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Then I try to get records based on the primary key
SELECT * FROM foo f where f.id IN (2, 3, 1);
I then get the following result
+----+--------+
| id | name |
+----+--------+
| 1 | first |
| 2 | second |
| 3 | third |
+----+--------+
3 rows in set (0.00 sec)
As one can see, the result is ordered by id. What I'm trying to achieve is to get the results ordered in the sequence I'm providing in the query. Given this example it should return
+----+--------+
| id | name |
+----+--------+
| 2 | second |
| 3 | third |
| 1 | first |
+----+--------+
3 rows in set (0.00 sec)
You could use a derived table with the IDs you want, and the order you want, and then join the table in, something like...
SELECT ...
FROM mcscb.mcs_premise prem
JOIN mcscb.mcs_serv_deliv_id serv
ON prem.prem_nb = serv.prem_nb
AND prem.tech_col_user_id = serv.tech_col_user_id
AND prem.tech_col_version = serv.tech_col_version
JOIN (
SELECT 1, '9486154876' FROM SYSIBM.SYSDUMMY1 UNION ALL
SELECT 2, '9403149581' FROM SYSIBM.SYSDUMMY1 UNION ALL
SELECT 3, '9465828230' FROM SYSIBM.SYSDUMMY1
) B (ORD, ID)
ON serv.serv_deliv_id = B.ID
WHERE serv.tech_col_user_id = 'CRSSJEFF'
AND serv.tech_col_version = '00'
ORDER BY B.ORD
You can use derived column to do custom ordering.
select
case
when serv.SERV_DELIV_ID = '9486154876' then 1 ELSE
when serv.SERV_DELIV_ID = '9403149581' then 2 ELSE 3
END END as custom_order,
...
...
ORDER BY custom_order
To make the logic a little bit more evident you might modify the solution provided by bhamby like so:
WITH ordered_in_list (ord, id) as (
VALUES (1, '9486154876'), (2, '9403149581'), (3, '9465828230')
)
SELECT ...
FROM mcscb.mcs_premise prem
JOIN mcscb.mcs_serv_deliv_id serv
ON prem.prem_nb = serv.prem_nb
AND prem.tech_col_user_id = serv.tech_col_user_id
AND prem.tech_col_version = serv.tech_col_version
JOIN ordered_in_list il
ON serv.serv_deliv_id = il.ID
WHERE serv.tech_col_user_id = 'CRSSJEFF'
AND serv.tech_col_version = '00'
ORDER BY il.ORD

PostgreSQL JSONB grouping array values inside a hash

We have a PostgreSQL jsonb column containing hashes which in turn contain arrays of values:
id | hashes
---------------
1 | {"sources"=>["a","b","c"], "ids"=>[1,2,3]}
2 | {"sources"=>["b","c","d","e","e"], "ids"=>[1,2,3]}
What we'd like to do is create a jsonb query which would return
code | count
---------------
"a" | 1
"b" | 2
"c" | 2
"d" | 1
"e" | 2
we've been trying something along the lines of
SELECT jsonb_to_recordset(hashes->>'sources')
but that's not working - any help with this hugely appreciated...
The setup (should be a part of the question, note the proper json syntax):
create table a_table (id int, hashes jsonb);
insert into a_table values
(1, '{"sources":["a","b","c"], "ids":[1,2,3]}'),
(2, '{"sources":["b","c","d","e","e"], "ids":[1,2,3]}');
Use the function jsonb_array_elements():
select code, count(code)
from
a_table,
jsonb_array_elements(hashes->'sources') sources(code)
group by 1
order by 1;
code | count
------+-------
"a" | 1
"b" | 2
"c" | 2
"d" | 1
"e" | 2
(5 rows)
SELECT h, count(*)
FROM (
SELECT jsonb_array_elements_text(hashes->'sources') AS h FROM mytable
) sub
GROUP BY h
ORDER BY h;
We finally got this working this way:
SELECT jsonb_array_elements_text(hashes->'sources') as s1,
count(jsonb_array_elements_text(hashes->'sources'))
FROM a_table
GROUP BY s1;
but Klin's solution is more complete and both Klin and Patrick got there quicker than us (thank you both) - so points go to them.

Migrate flat jsonb to hstore

I run postgres 9.4, and want to migrate column in my database table to hstore just to be able to make performance comparison.
My current column is key-value pair in jsonb, w/o nested structure.
Any tips how to approach this problem?
Example data:
create table jsons (id int, val jsonb);
insert into jsons values
(1, '{"age":22}'),
(2, '{"height":182}'),
(3, '{"age":30, "height":177}');
Split json objects to key, value pairs:
select id, (jsonb_each_text(val)).key, (jsonb_each_text(val)).value
from jsons
id | key | value
----+--------+-------
1 | age | 22
2 | height | 182
3 | age | 30
3 | height | 177
(4 rows)
Aggregate the pairs and convert them to hstore:
select id, hstore(array_agg(key), array_agg(value))
from (
select id, (jsonb_each_text(val)).key, (jsonb_each_text(val)).value
from jsons
) sub
group by 1
order by 1
id | hstore
----+------------------------------
1 | "age"=>"22"
2 | "height"=>"182"
3 | "age"=>"30", "height"=>"177"
(3 rows)
The same can be accomplished in a more elegant way using lateral join:
select id, hstore(array_agg(key), array_agg(value))
from jsons
cross join jsonb_each_text(val)
group by 1
order by 1;