Array Insertion Postgres - postgresql

I have a table item with attributes no(integer) and price(integer), also another table cart with attributes no(integer) and items(array of item).
I have some records in items.
When i tried :
INSERT INTO myschema.cart VALUES(1,'{SELECT item from myschema.item}')
I'am getting error malformed record literal.
I expected this to insert all items from myschema.item into the cart record.

It's hard to give you exact statement without the table structures and such, but you can select into an array:
INSERT INTO myschema.cart (id, item_ids)
SELECT 1, array(SELECT id from myschema.item)
This will select the id's from the item table into an array.
You can test it out by writing:
select array(SELECT id from myschema.item)

You can't write a subquery inside a string like that.
What you need to do is aggregate the items into a array with array_agg
INSERT INTO myschema.cart
VALUES (1, (SELECT array_agg(item) FROM myschema.item));
Or
INSERT INTO myschema.cart
SELECT 1, array_agg(item) FROM myschema.item;

Related

Extract all the values in jsonb into a row

I'm using postgresql 11, I have a jsonb which represent a row of that table, it's look like
{"userid":"test","rolename":"Root","loginerror":0,"email":"superadmin#ae.com",...,"thirdpartyauthenticationkey":{}}
is there any method that I could gather all the "values" of the jsonb into a string which is separated by ',' and without the keys?
The string I want to obtain with the jsonb above is like
(test, Root, 0, superadmin#ae.com, ..., {})
I need to keep the ORDER of those values as what their keys were in the jsonb. Could I do that with postgresql?
You can use the jsonb_populate_record function (assuming your json data does match the users table). This will force the text value to match the order of your users table:
Schema (PostgreSQL v13)
CREATE TABLE users (
userid text,
rolename text,
loginerror int,
email text,
thirdpartyauthenticationkey json
)
Query #1
WITH d(js) AS (
VALUES
('{"userid":"test", "rolename":"Root", "loginerror":0, "email":"superadmin#ae.com", "thirdpartyauthenticationkey":{}}'::jsonb),
('{"userid":"other", "rolename":"User", "loginerror":324, "email":"nope#ae.com", "thirdpartyauthenticationkey":{}}'::jsonb)
)
SELECT jsonb_populate_record(null::users, js),
jsonb_populate_record(null::users, js)::text AS record_as_text,
pg_typeof(jsonb_populate_record(null::users, js)::text)
FROM d
;
jsonb_populate_record
record_as_text
pg_typeof
(test,Root,0,superadmin#ae.com,{})
(test,Root,0,superadmin#ae.com,{})
text
(other,User,324,nope#ae.com,{})
(other,User,324,nope#ae.com,{})
text
Note that if you're building this string to insert it back into postgresql then you don't need to do that, since the result of jsonb_populate_record will match your table:
Query #2
WITH d(js) AS (
VALUES
('{"userid":"test", "rolename":"Root", "loginerror":0, "email":"superadmin#ae.com", "thirdpartyauthenticationkey":{}}'::jsonb),
('{"userid":"other", "rolename":"User", "loginerror":324, "email":"nope#ae.com", "thirdpartyauthenticationkey":{}}'::jsonb)
)
INSERT INTO users
SELECT (jsonb_populate_record(null::users, js)).*
FROM d;
There are no results to be displayed.
Query #3
SELECT * FROM users;
userid
rolename
loginerror
email
thirdpartyauthenticationkey
test
Root
0
superadmin#ae.com
[object Object]
other
User
324
nope#ae.com
[object Object]
View on DB Fiddle
You can use jsonb_each_text() to get a set of a text representation of the elements, string_agg() to aggregate them in a comma separated string and concat() to put that in parenthesis.
SELECT concat('(', string_agg(value, ', '), ')')
FROM jsonb_each_text('{"userid":"test","rolename":"Root","loginerror":0,"email":"superadmin#ae.com","thirdpartyauthenticationkey":{}}'::jsonb) jet (key,
value);
db<>fiddle
You didn't provide DDL and DML of a (the) table the JSON may reside in (if it does, that isn't clear from your question). The demonstration above therefore only uses the JSON you showed as a scalar. If you have indeed a table you need to CROSS JOIN LATERAL and GROUP BY some key.
Edit:
If you need to be sure the order is retained and you don't have that defined in a table's structure as #Marth's answer assumes, then you can of course extract every value manually in the order you need them.
SELECT concat('(',
concat_ws(', ',
j->>'userid',
j->>'rolename',
j->>'loginerror',
j->>'email',
j->>'thirdpartyauthenticationkey'),
')')
FROM (VALUES ('{"userid":"test","rolename":"Root","loginerror":0,"email":"superadmin#ae.com","thirdpartyauthenticationkey":{}}'::jsonb)) v (j);
db<>fiddle

can't select data from a dictionary inside a list

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

Bulk INSERT for records that don't exist, returning ID

I'm using pg-promise to process an array of data that I want to insert in table A. I'm having a hard time figuring out how to dynamically create this query that should only INSERT those values not already present in the table, while returning the ID of all those who are already present or were newly created.
I'm doing the following to do the above, but for a single element:
WITH s as
( SELECT *
FROM fruits
WHERE fruit_name = 'Apple' ),
i AS
( INSERT INTO fruits(fruit_name) SELECT 'Apple'
WHERE NOT exists
(SELECT 1
FROM s) RETURNING fruit_id)
But say that I have an Array of fruits = ['Banana', 'Apple']. How would I use the helpers to generate a query that would return the existing ID for apple, and the one for Banana?

Inserting records into table1 depending on row value in table2

For each row in table exam 'where exam.examRegulation isnull', I want to insert one corresponding row in table examRegulation and copy columnvalues from exam to examregulation. Apparently the following query ist too naive and must be approved:
insert into examRegulation (graduation, course, examnumber, examversion)
values (exam.graduation, exam.course, exam.examnumber, exam.examversion)
where ?? (select graduation, course, examnumber, examversion
from exam
where exam.examRegulation isnull)
Is there a way to do this in postgresql?
You may rephrase this as an INSERT INTO ... SELECT statement:
INSERT INTO examRegulation (graduation, course, examnumber, examversion)
SELECT graduation, course, examnumber, examversion
FROM exam
WHERE examRegulation IS NULL;
The VALUES clause, as the name implies, can only be used with literal values. If you need to populate an insert using query logic, then you need to use a SELECT clause.

How to include the values of a select statement in an insert? (PostgreSQL)

I have this select statement:
select it.item_id
from item as it
where it.owning_collection in (select col.collection_id
from collection as col
where col.name like '%Restricted%'
Which returns around 3k results. Now I would like to make an insert in another table for each one of those results with that item_id as one of the parameters like this:
insert into metadatavalue (metadata_value_id, **item_id**, metadata_field_id, text_value, text_lang, place, confidence)
But since I'm not very experienced with databases, I'm not sure how to make these multiple inserts
All the other information needed in the insert statement are fixed values.
Table structures:
Table Item
*item_id
*submitter_id
*in_archive
*withdrawn
*last_modified
*owning_collection
*dicoverable
Table metadata
*metadata_value_id
*item_id
*metadata_field_id
*text_value
*text_lang
*place
*authority
*confidence
insert into metadatavalue (metadata_value_id, item_id, metadata_field_id, text_value, text_lang, place, confidence)
select 'metadata_value_id',it.item_id,'metadata_field_id','text_value', 'text_lang', 'place', 'confidence'
from item it
where it.owning_collection in (select col.collection_id
from collection as col
where col.name like '%Restricted%')
Replace 'apostrophed' columns with its default values.
Further reading.
INSERT INTO metadatavalue (item_id, metadata_field_id, text_value, text_lang, place, confidence)
SELECT it.item_id, <c1>, <c2>, <c3>, <c4>, <c5>
FROM item AS it
JOIN collection AS col ON col.collection_id = it.owning_collection
WHERE col.name LIKE '%Restricted%'
Where you replace <c1> etc with your constant values. Note also that I have rewritten your SELECT query to a more efficient JOIN.