Insert into 2 tables with single SQL statement instead of loop - sql

I have to insert data in provonance of several table which itself comes from csv (COPY).
Before I used a LOOP in a function to enter the data. I want to simplify the thing for the sake of maintainability and speed.
I need to insert data into a description table, which serves as both the title and description (and multi language).
Previously my code was as follows (extract from the loop):
insert into description (label, lang_id, poi_id,date_dernier_update, date_enregistrementbdd, date_derniere_lecture) values (label, lang_id, poi_id, now(), now(), now()) RETURNING id INTO _retour_id_titre;
insert into poi_titre_poi (poi_id, titre_poi_id, titre_poi_key) values (poi_id, _retour_id_titre, label_lang);
But now I can't:
with rows as (
insert into description (label, lang_id, poi_id)
select rdfslabelfrs, '1', (select id from poi where uri_id = csv_poi_rdf_fr.poi) as toto from csv_poi_rdf_fr RETURNING id
)
insert into poi_titre_poi (poi_id, titre_poi_id, titre_poi_key)
select description.poi_id, id , 'fr'
FROM description;
In fact, I cannot insert the 'poi_id' in the 'poi_titre_poi' table which corresponds to the one which was inserted in the description table.
I get this error message:
ERROR: more than one row returned by a subquery used as an expression
État SQL : 21000
Can I make this work, or do I need to loop?

Filling in missing bits with assumptions, it could work like this:
WITH description_insert AS (
INSERT INTO description
(label , lang_id, poi_id)
SELECT c.rdfslabelfrs, 1 , p.id
FROM csv_poi_rdf_fr c
JOIN poi p ON p.uri_id = c.poi
RETURNING poi_id, id
)
INSERT INTO poi_titre_poi (poi_id, titre_poi_id, titre_poi_key)
SELECT d.poi_id, d.id , 'fr'
FROM description_insert d;
Related:
PostgreSQL multi INSERT...RETURNING with multiple columns
Insert data in 3 tables at a time using Postgres
Get Id from a conditional INSERT

Related

Join with json column?

I need find rows in table users by joining column in table queries.
I wrote some sql but it takes 0.200s to run, when SELECT * FROM ... takes 0.80s.
How can I improve performance?
db-fiddle example
The tables are :
CREATE TABLE users (
id INT,
browser varchar
);
CREATE TABLE queries (
id INT,
settings jsonb
);
INSERT INTO users (id,browser) VALUES (1, 'yandex');
INSERT INTO users (id, browser) VALUES (2, 'google');
INSERT INTO users (id, browser) VALUES (3, 'google');
INSERT INTO queries (id, settings) VALUES (1, '{"browser":["Yandex", "TestBrowser"]}');
and the query :
select x2.id as user_id, x1.id as query_id
FROM (
SELECT id, json_array_elements_text((settings->>'browser')::JSON) browser
FROM queries) x1
JOIN users x2 ON lower(x1.browser::varchar) = lower(x2.browser::varchar)
group by 1,2;
json_array_elements_text((settings->>'browser')::JSON)
'->>' converts the result to text. Then you cast it back to JSON. Doing that on one row (if you only have one) is not really going to be a problem, but it is rather pointless.
You could instead do:
jsonb_array_elements_text(settings->'browser')
ON lower(x1.browser::varchar) = lower(x2.browser::varchar)
You can create an index that can be used for this:
create index on users (lower(browser));
It won't do much good on a table with 3 rows. But presumably you don't really have 3 rows.

PostgreSQL 9.3 - How to insert using json_populate_recordset but still get auto ids by sequence

This is a followup question to "Populate multiple tables from a single JSON object with json_populate_recordset".
Say my tables (table_a, table_b) have sequences for a_id and b_id,
so they look like this:
CREATE TABLE table_a (a_id serial, b_id integer, c_id integer);
CREATE TABLE table_b (b_id serial, name text, z_id integer);
...
CREATE TABLE table_z (z_id serial, some_text_entry text);
A regular insert looking like this
INSERT INTO table_a (b_id, c_id) values (1, 2);
INSERT INTO table_b (name, z_id) values ("whatever", 3);
...
INSERT INTO table_z (some_text_entry) values ("Some text");
lets PostgreSQL increment the ids for a_id (table_a), b_id(table_b), etc., so the new dataset can be created and stored.
But how could I insert data using the more complex approach following and still get automatically created ids?
WITH input AS (
SELECT '{
"tablename_a":[{"a_id":1,"b_id":2,"c_id":3},
{"a_id":2,"b_id":51,"c_id":3}],
"tablename_b":[{"b_id":2,"name":"John Doe", "z_id":123},
{"b_id":51,"name":"Mary Ann", "z_id":412}],
"tablename_z":[{"z_id":123, "some_text_entry":"Something"},
{"z_id":123, "some_text_entry":"Something else"}]
}'::json AS j
)
, a AS (
INSERT INTO tablename_a
SELECT t.*
FROM input i
, json_populate_recordset(NULL::tablename_a, i.j->'tablename_a') t
)
, b AS (
INSERT INTO table_b
SELECT t.*
FROM input i
, json_populate_recordset(NULL::tablename_b, i.j->'tablename_b') t
)
-- ... more ...
INSERT INTO tablename_z
SELECT t.*
FROM input i
, json_populate_recordset(NULL::tablename_z, i.j->'tablename_z') t
;
If I just set the id to null
"tablename_a":[{"a_id": null,"b_id":2,"c_id":3},
{"a_id": null,"b_id":51,"c_id":3}]
or leave out the respective ids like this:
"tablename_a":[{"b_id":2,"c_id":3},
{"b_id":51,"c_id":3}]
I get the error 'null value in column "a_id" violates not-null constraint'.
In addition:
Would be really great if there was a way to deal with this, without specifically listing all column names (except the serial-ones).
In MySQL if you take my table_a, I know you could do something like
INSERT INTO table_a VALUES (1,2)
meaning that MySQL would fill the a_id field with an autoincrement id and the rest with the data given by the insert command. Is there no way to accomplish that with json, too?
Usually, when you want to insert into a table that has a column of type serial or bigserial, you omit that column from the list of columns. I tried to change your original syntax as little as possible to show how this works.
-- I made no changes to the CTE, except to cut some lines.
WITH input AS (
SELECT '{
"tablename_a":[{"a_id":1,"b_id":2,"c_id":3}, {"a_id":2,"b_id":51,"c_id":3}]
}'::json AS j
)
-- Ignore a_id. It's set automatically by PostgreSQL.
-- Think about cutting it from input.
INSERT INTO table_a (b_id, c_id)
SELECT b_id, c_id
FROM input i
, json_populate_recordset(NULL::table_a, i.j->'tablename_a') t

Inserting the data at a time in 3 tables using an array into Postgresql database

I have to insert the data at a time in 3 tables into PostgreSQL database.
I have to insert data into first and Second table is directly.
But The third table which i received data as array and inserted into 3rd table as same.
Is data inserting as array into PostgreSQL available or possible?
If it possible how can I insert can some correct me
How can i do the same mechanism with Wso2 DSS 3.0.1.
My query is
with first_insert as (insert into sample(name,age)
values(?,?)
RETURNING id
),
second_insert as (insert into sample1(empid,desig)
values((select id from first_insert),?)
RETURNING userid
)
insert into sample2(offid,details)
values((select userid from second_insert),?)
Not sure I understood your question exactly, but at least you could use insert into ... select:
with cte_first_insert as
(
insert into sample1(name, age)
values('John', 25)
returning id
), cte_second_insert as (
insert into sample2(empid, desig)
select id, 1 from cte_first_insert
returning userid
)
insert into sample3(offid, details)
select userid, 'test'
from cte_second_insert;
sql fiddle demo

SQL INSERT statement for TWO TABLES at time with INNER JOIN

I have two tables hello and login_table and below is their structure
user_info
-------
some_id | name | address
login_table
-------
id | username | password
some_id and id are autoincrement indexes.
Now how can i use INSERT statement with INNER JOIN in SQL
at present, i want add below data with same some_id and id
`name` = John
`address` = wall street
`username` = john123
`password` = passw123
below code shows, what i have tried so far.
insert into login_table lt
INNER JOIN user_info ui ON ui.some_id = lt.id
(ui.name, ui.address, lt.username, lt.password)
values
('John', 'wall street', 'john123', 'passw123')
And this is not the one value, i want to add more than one value at a time.. how can i achieve.
thanks for help.
If you need to perform the two INSERT operations atomically, use a transaction:
START TRANSACTION;
INSERT INTO login_table (username, password) VALUES ('john123', 'passw123');
INSERT INTO user_info (name, address) VALUES ('John', 'wall street');
COMMIT;
N.B. Your storage engine must support transactions for this to work (e.g. InnoDB).
To insert multiple values into a table at once, use the multiple rows form of INSERT. As stated in the manual:
INSERT statements that use VALUES syntax can insert multiple rows. To do this, include multiple lists of column values, each enclosed within parentheses and separated by commas. Example:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
The values list for each row must be enclosed within parentheses. The following statement is illegal because the number of values in the list does not match the number of column names:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3,4,5,6,7,8,9);
VALUE is a synonym for VALUES in this context. Neither implies anything about the number of values lists, and either may be used whether there is a single values list or multiple lists.
Insert to two tables is impossible. The second part of your question is possible: you can insert multiple rows in one statement like this:
insert into some_table(col1, col2) values (1,2), (3,4), (5,6);
USE [ERPDb]
GO
INSERT INTO [AAA].[UserRole] ([UserId], [RoleId])
SELECT u.Id, (SELECT Id FROM [AAA].[Role] WHERE Title = 'Employee') FROM [AAA].[User] u
INNER JOIN [dbo].[BaseDealer] bd ON u.Id = bd.Id
WHERE bd.DealerType = 0
GO

Complex insert statements

I want to ask is it possible to insert your own value in the table as well as select other values in other table? I have tried to come out with my select and insert statement but i'm missing one statement as i want to insert my own values in rather than referencing it.
All my required tables have been created. And I wish to insert my own values like Type and rest of the insert values will be selected from other tables.
Below is my code: (Am i missing a statement?)
Insert Into Test (Test_Date, Testno, Examno, Serialno, Type, Hours)
Select S.Test_Date, E.Testno, S.Examno, S.Serialno, Type, (F.STARTED- F.ENDED) as hours
From Semester S, TIME F, TESTPAPERS e
Where S.Testno = F.Testno
And E.Testno = 1
and TYPE = 'Non-FLight'; -- this is the statement that i wish to insert own values instead and not selecting.
Is it possible to do all in one insert statement ? I don't wish to update my table so many times just to insert type value.
Thanks
Just put the value you would like for Type in your select statement:
Insert Into Test (Test_Date, Testno, Examno, Serialno, Type, Hours)
Select S.Test_Date, E.Testno, S.Examno, S.Serialno, 'Non-Flight', (F.STARTED- F.ENDED) as Hours
From Semester S, TIME F, TESTPAPERS e
Where S.Testno = F.Testno And E.Testno = 1