INSERT output of a subquery along with an autoincrement in postgres - postgresql

I am trying to store the output of a WITH statement in an INSERT statement in postgres along with an autoincrement id.
Below is the query:
INSERT
INTO
table
(row_id,(
SELECT
*
FROM
final_dataset
));
However, I am getting a syntax error near "SELECT". I am unabe to figure out the solution to this.

Are you looking for this?
insert into the_table (col1, col2, col3)
select nextval('the_table_id_seq'), x1, x2
from final_dataset;
If col1 is a serial or identitycolumn, I would remove it completely:
insert into the_table (col2, col3)
select x1, x2
from final_dataset;

Related

RETURNING in INSERT INTO statement with a SELECT statement

I am inserting data into a table and want to return the inserted data. The inserted data contains foreign keys. I would like to get the whole data with the joins of the foreign keys.
I have tried putting a SELECT in RETURNING without luck. Is this even possible or do I just have to do another query after inserting the data?
Insert statement:
INSERT INTO someTable (col1, col2, col3, foreign_id)
VALUES ('value1', 'value2', 'value3', 1);
So in this case, could I have a RETURNING that basically would give me:
SELECT someTable.*, foreignTable.*
FROM someTable
JOIN foreignTable ON someTable.foreign_id = foreignTable.id;
demo:db<>fiddle
You can use a CTE for this:
WITH inserting AS (
INSERT INTO...
RETURNING <new data>
)
SELECT i.*, ft.*
FROM inserting i JOIN foreign_table ft ...
In this case the INSERT statement will be executed. The SELECT statement will be executed after that. This can reference the inserted data.
You can use a CTE for that:
with new_row as (
INSERT INTO some_table (col1, col2, col3, foreign_id)
VALUES ('value1', 'value2', 'value3', 1)
returning *
)
SELECT new_row.*, ft.*
FROM new_row
JOIN foreign_table ft ON new_row.foreign_id = ft.id;

Upsert if on conflict occurs on multiple columns in Postgres db

I have a table in Postgres db with no primary keys. I want to update if the combination of 2 columns have the same value.
...
ON CONFLICT (col1, col2)
DO UPDATE
ELSE
INSERT
...
I couldn't find anything without primary keys. Also, the combination of col1 and col2 is unique. There could be multiple rows for col1 with the same value or with col2 but together cannot.
So my table is something like this:
col1 col2
1 A
1 B
2 A
2 B
I cannot have a unique constraint on either of these columns but adding the index together in a combination works as follows:
CREATE TABLE example (
col1 integer,
col2 integer,
col3 integer,
UNIQUE (col1, col2));
But now, how to handle the inserts. What should be the ON CONFLICT condition as we cannot have on 2 columns so back to the same issue.
Actually, found it here but not in the post marked as answer but the most rated post. Use multiple conflict_target in ON CONFLICT clause
So our query will be as follows:
INSERT into example (col1, col2, col3)
VALUES (1, 2, 3)
ON CONFLICT (col1, col2) DO UPDATE
SET col3 = 42

Postgres EXECUTE with CTE

Is it possible to EXECUTE a prepared statement using parameters you'd get from a CTE ?
The below samples are simplified versions of my code, but this is replicating exactly the problem I have.
Here's how far I've been able to go - without a CTE :
BEGIN;
CREATE TEMPORARY TABLE testTable
(
col1 NUMERIC,
col2 TEXT
) ON COMMIT DROP;
INSERT INTO testTable
VALUES (1, 'foo'), (2, 'bar');
PREPARE myStatement AS
WITH cteTable AS
(
SELECT col1, col2
FROM testTable
WHERE col1 = $1
)
SELECT col2 FROM cteTable;
EXECUTE myStatement(2);
DEALLOCATE myStatement;
COMMIT;
Here's the result:
col2
bar
And now, here's what I am trying to achieve :
BEGIN;
CREATE TEMPORARY TABLE testTable
(
col1 NUMERIC,
col2 TEXT
) ON COMMIT DROP;
INSERT INTO testTable
VALUES (1, 'foo'), (2, 'bar');
PREPARE myStatement AS
WITH cteTable AS
(
SELECT col1, col2
FROM testTable
WHERE col1 = $1
)
SELECT col2 FROM cteTable;
-- Using a CTE here to get the parameters for the prepared statement
WITH parameters AS
(
SELECT 2 val
)
EXECUTE myStatement(SELECT val FROM parameters);
DEALLOCATE myStatement;
COMMIT;
The error message I'm having is
Syntax error at or near EXECUTE
Even if try to run the EXECUTE part without attempting to use the CTE values, I still have the same error message.
As I haven't been able to find anyone else having the same issue despite my researches, I guess I could be doing it wrong.. If so could someone please point me into the right direction ?
Thanks
As Vao Tsun commented, this is not possible.
I have converted my prepared statement to a function which will return a table, then used a CTE to SELECT UNION my function with multiple parameters.

Copy rows into same table, but change value of one field

I have a list of values:
(56957,85697,56325,45698,21367,56397,14758,39656)
and a 'template' row in a table.
I want to do this:
for value in valuelist:
{
insert into table1 (field1, field2, field3, field4)
select value1, value2, value3, (value)
from table1
where ID = (ID of template row)
}
I know how I would do this in code, like c# for instance, but I'm not sure how to 'loop' this while passing in a new value to the insert statement. (i know that code makes no sense, just trying to convey what I'm trying to accomplish.
There is no need to loop here, SQL is a set based language and you apply your operations to entire sets of data all at once as opposed to looping through row by row.
insert statements can come from either an explicit list of values or from the result of a regular select statement, for example:
insert into table1(col1, col2)
select col3
,col4
from table2;
There is nothing stopping you selecting your data from the same place you are inserting to, which will duplicate all your data:
insert into table1(col1, col2)
select col1
,col2
from table1;
If you want to edit one of these column values - say by incrementing the value currently held, you simply apply this logic to your select statement and make sure the resultant dataset matches your target table in number of columns and data types:
insert into table1(col1, col2)
select col1
,col2+1 as col2
from table1;
Optionally, if you only want to do this for a subset of those values, just add a standard where clause:
insert into table1(col1, col2)
select col1
,col2+1 as col2
from table1
where col1 = <your value>;
Now if this isn't enough for you to work it out by yourself, you can join your dataset to you values list to get a version of the data to be inserted for each value in that list. Because you want each row to join to each value, you can use a cross join:
declare #v table(value int);
insert into #v values(56957),(85697),(56325),(45698),(21367),(56397),(14758),(39656);
insert into table1(col1, col2, value)
select t.col1
,t.col2
,v.value
from table1 as t
cross join #v as v

postgres: Setting the value of an array with a subquery?

In postgres, can you set the value of an array in an INSERT to the result of a subquery? Like:
INSERT INTO mytable
VALUES( SELECT list_of_integers FROM someothertable WHERE somekey = somevalue);
Where that mytable just has as its one column a type of integer[] and that other column list_of_integers is also type integer[] ?
You want the unnest function. I think you'd use it like:
INSERT INTO mytable
SELECT set_of_integers
FROM unnest(
SELECT list_of_integers
FROM someothertable
WHERE somekey = somevalue
) t(set_of_integers)
But i don't have PostgreSQL to hand to try it out myself.
Yes:
INSERT INTO
mytable
(column1, column2, an_array_of_integers_column)
VALUES
(2, 'bbb', (SELECT list_of_integers FROM someothertable WHERE somekey = somevalue));