PostgreSQL JSON array value from another column - sql

I have employee table in postgreSQL
CREATE TABLE Employee(EmployeeID integer PRIMARY KEY AUTO_INCREMENT,
Employeename VARCHAR(100));
alter table Employee add column parents JSON;
Now, I want to update JSON column with JSON array with a value from the existing column like below.
update employee set parents = json_array_elements('[{"name":Employeename, "id":EmployeeID }]')
Any way I can achieve this?

Try using:
JSON_BUILD_OBJECT function, to generate your json element
JSON_BUILD_ARRAY function, to enclose your json object into an array
UPDATE employee
SET parents = JSON_BUILD_ARRAY(
JSON_BUILD_OBJECT('name', Employeename,
'id' , EmployeeID ));
Check the demo here.
If you need to store it as an array, since

Related

How to append to the value of a given key in a json column?

I have user_product_mapping storing product per user:
DROP TABLE IF EXISTS user_product_mapping;
CREATE TABLE user_product_mapping
(
id SERIAL NOT NULL PRIMARY KEY,
user_id INT,
product_info json NOT NULL,
CONSTRAINT fk_user FOREIGN KEY(user_id) REFERENCES users(user_id)
);
Sample values:
INSERT INTO user_product_mapping (user_id, product_info)
VALUES
(1, '{"product": "laptop,mobile"}'),
(2, '{"product": "charger"}'),
(3, '{"product": "mobile,mouse,charger"}')
;
Now I want to add a new product as 'laptop' to existing user_id 2.
Expected result:
user_id | product_info
---------------------------------------
2 | {"product": "charger,laptop"}
I have tried to append but face an issue:
UPDATE user_product_mapping
SET product_info = product_info || '{"laptop"}'
WHERE user_id = 2;
Error:
ERROR: column "product_info" is of type json but expression is of type text
LINE 2: SET product_info = product_info || '{"123e4567-e89b-12d3-a45...
^
HINT: You will need to rewrite or cast the expression.
Can you please suggest the way forward.
UPDATE user_product_mapping
SET product_info = json_build_object('product', concat_ws(',', NULLIF(product_info->>'product', ''), 'laptop'))
WHERE user_id = 2;
Even works properly with a missing 'product' key, one with a null value, or an empty list. But it's putting lipstick on a pig.
It burns down to extracting the text value, concatenating another item to the list (safely), and assigning a newly wrapped JSON value. See:
How to concatenate columns in a Postgres SELECT?
While using JSON, the data type jsonb would be more practical, so you can use jsonb_set():
SET product_info = jsonb_set (product_info, '{product}', to_jsonb(concat_ws(',', NULLIF(product_info->>'product', ''), 'laptop')))
More practical, yet, with a JSON array instead of that list of text values.
SET product_info = product_info || jsonb '"laptop"'
And that would be more practical as Postgres array of text: text[], yet.
SET product_info = product_info || 'laptop'
But what you probably really should do is a properly normalized many-to-many implementation:
How to implement a many-to-many relationship in PostgreSQL?
How to perform update operations on columns of type JSONB in Postgres 9.4
Then you add and remove products with a plain INSERT or DELETE, not causing problems with concurrent writes for the same user like all of the above will.

JSON_QUERY with Column values

One of my tables contains JSON values in each row of a column.
The data is as below (example. one row)
[{"id":"30a66bec-c0aa-4655-a8ef-506e52bfcc14","type":"nps","value":"promoter","decimalValue":"10"},{"id":"37850b3b-1eac-4921-ae22-b2f6d2450897","type":"sentiment","value":"positive","decimalValue":"0.990000009536743"}]
Now I'm trying to retrieve two columns from it. (id, value)
I'm writing the below query using JSON_VALUE but getting NULL values in each row of the new column.
select a.jsondata,JSON_VALUE(a.jsondata,'$.id') from table as a
Your JSON field is an array so you need to specify which element you're after, assuming its always the first you can use:
select a.jsondata,JSON_VALUE(a.jsondata,'$[0].id') from table as a
You need to change the index inside the square brackets to access the id you want from the JSON string
You have a JSON array. If you want to break it into multiple rows you need to use OPENJSON
SELECT j.*
FROM YourTable t
CROSS APPLY OPENJSON (t.Json)
WITH (
id uniqueidentifier,
value varchar(100)
) j;
db<>fiddle

Making an array of keys from json in postgresSQL

I have column "elements" in table which is having a json(array json) row values which looks like this
elements
[{"key":12,"value":"qw"},{"key":13,"value":"fa"}]
[{"key":32,"value":"24"},{"key":321,"value":"21"}]
I want to make an column of arrays for every row which consist of keys extracted from that row's json values ,my desired column "result" may look like this
elements
result
[{"key":12,"value":"qw"},{"key":13,"value":"fa"}]
{12,13}
[{"key":32,"value":"24"},{"key":321,"value":"21"}]
{32,321}
is there a way to do it? thank you
Schema (PostgreSQL v13)
CREATE TABLE test (
elements json
);
INSERT INTO test VALUES ('[{"key":12,"value":"qw"},{"key":13,"value":"fa"}]');
INSERT INTO test VALUES ('[{"key":32,"value":"24"},{"key":321,"value":"21"}]');
Query #1
select elements::text, array_agg(cast(value->>'key' as integer)) as result
from test, json_array_elements(elements)
group by 1
ORDER BY 1;
elements
result
[{"key":12,"value":"qw"},{"key":13,"value":"fa"}]
12,13
[{"key":32,"value":"24"},{"key":321,"value":"21"}]
32,321
View on DB Fiddle
select elements::text,
array_agg(value->>'key')
from your_table, json_array_elements(elements)
group by 1;

Get value based on column name stored in another table

I have following tables structure:
"DocumentSubject"
(
"Id" SERIAL NOT NULL,
"Description" text,
"List1Left" text,
"List1Right" text
);
"DocumentRegistryAttributes"
(
"Id" SERIAL NOT NULL,
"DocumentSubjectId" integer,
"Code" text,
"WorkDetails" text,
"Name" text
);
In DocumentSubject there is column named List1Left which contains a name of column from DocumentRegistryAttributes table f.e. Code.
Can I retrieve value of column Code from DocumentRegistryAttributes based on string column name stored in DocumentSubject table?
I need something like this:
"DocumentRegistryAttributes"["DocumentSubject"."List1Left"] <-- first get value of column "List1Left" from table "DocumentSubject", and then retrieve this column value from "DocumentRegistryAttributes" table.
Here is fiddle: http://www.sqlfiddle.com/#!17/6cbc3/1
The real problem is, that I cannot use any static conditions in WHERE clause. Each document in DocumentRegistryAttributes table can be assigned to different subject in DocumentSubject table, and each subject can have different configuration.
Is it possible?
You can use to_jsonb() to make a JSON for the row from "DocumentRegistryAttributes", with the column names as keys and then select the text from the JSON where the key is the text in "DocumentSubject"."List1Left".
SELECT *,
to_jsonb(dra)->>ds."List1Left"
FROM "DocumentSubject" ds
LEFT JOIN "DocumentRegistryAttributes" dra
ON dra."DocumentSubjectId" = ds."Id";

use nested table value in where clause(oracle)

i am fairly new to the Oracle DBMS and would like to know how to use a member of a nested table in a where clause
specifically
i have a nested table named poll_nest
SQL> desc poll_nest
Name Null? Type
----------------------------------------- -------- ----------------------------
ID VARCHAR2(20)
CID VARCHAR2(20)
which was created as follows
create or replace type voter_arrive as object(id varchar(20),cid varchar(20));
create or replace type poller as table of voter_arrive;
and then it was inserted into the election table as poll_nest
SQL> desc election;
Name Null? Type
----------------------------------------- -------- ----------------------------
REGION VARCHAR2(20)
STIME TIMESTAMP(6)
ETIME TIMESTAMP(6)
VOTES POLLER
i need to take some actions based on the value of the cid attribute of poll_nest that is currently entered(like incrementing a value based on the cid)
so i used an after trigger in which i did this:
select distinct t.cid into voted from election e,table(e.votes) t where t.cid=:new.votes.cid;
but i get a compilation error.
i saw this answer and this too:
Oracle Nested Table predicate in where clause
but couldn't understand how they work..
could someone please help me with the syntax?
poll_nest is not a nested table. Its table that stores PL SQL object.
From http://www.orafaq.com/wiki/NESTED_TABLE :
NESTED TABLE is an Oracle data type used to support columns containing multivalued attributes, in this case, columns that can hold an entire sub-table.
You can insert value in table of object type by first instantiating object constructor like
insert into poll_nest values (voter_arrive('122','112'));
For accessing the inserted value you can use
select e.voter.arrive.cid from poll_tab e where e.voter_arrive.id = '122';
check out this link too: http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/objects.htm
Update:
I looked up oracle documentation http://docs.oracle.com/cd/A97630_01/appdev.920/a96624/05_colls.htm , and I found that poller is a nested table. I don't know why they call it nested table, it should be called PL/SQL table only.
I assumed poll_nest to be like, and answered the question
CREATE TABLE APPS.POLL_NEST
(
VOTER APPS.VOTER_ARRIVE
)
but now I think you have created table and objects like
create or replace type voter_arrive as object(id varchar(20),cid varchar(20));
create or replace type poller as table of voter_arrive;
create table election(
REGION VARCHAR2(20),
STIME TIMESTAMP(6),
ETIME TIMESTAMP(6),
VOTES POLLER
) NESTED TABLE VOTES STORE AS VOTES_TAB;
For each region(which should be unique), you are going to save records in VOTES nested table .if I am correct
INSERT INTO election
VALUES ( 'A',
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP,poller(voter_arrive('100','001'),voter_arrive('200','002')) )
poller() is a constructor of nested table type poller. All values passed to constructor will create new row in poller. So, you can perform insert and update in election table like
INSERT INTO table (select e.votes from election e where region ='A') values((voter_arrive('300','003')))
To access individual row in poller nested table you need to use TABLE() function like this:
select * from table (select e.votes from election e where region ='A') a where a.id = 100