Get last id before transaction commit using postgres in Golang - postgresql

I have 2 insert queries.
In the second insert query, I need the first insert returned id.
I am doing those queries as a transaction, because they depend each other.
So, is it possible to get the last insert id before committing transaction in postgres in Golang.

Postgres supports the returning keyword to select the inserted id:
INSERT INTO YourTable (col1, col2) VALUES ('Value1', 'Value2') RETURNING id;

Related

Is update by select atomic for READ_COMMITED in postgres?

Is following query atomic within READ_COMMITED transaction?
update my_table
set
owner = ?,
where id = (
select id from my_table
where owner is null
limit 1
) returning *
I run tests on local postgres instance and it seems to be atomic, but is this always the case?
Each SQL statement in READ COMMITTED isolation level takes a snapshot of the database, so it and all its subqueries see a consistent version of the database.
But you are not safe from “lost updates”: it is possible that a concurrent transaction modifies a row between the start of the statement and the time the row is updated, so it could be that the row that is actually updated does not have owner set to NULL any more.
If you need to avoid that, add a FOR UPDATE clause in the subquery.

Good Pattern for executing SELECT after INSERT with Amazon Aurora Postgres?

Imagine you have an Amazon Aurora Postgres DB. You perform an INSERT into one table. You then need do a SELECT to get the auto-generated CompanyId of the newly added record. You determine that there is often a significant enough delay between when the INSERT occurs and when the record is available to run the SELECT on.
I've discussed with my colleagues some possible code patterns to best handle this lag time. What, in your opinion, is the best approach?
You don't need a separate SELECT statement. The best and most efficient option is to just use the returning clause:
insert into some_table (c1, c2, c3)
values (...)
returning *;
Instead of returning * you can also specify the column you want, e.g.: returning company_id
Another other option is to use currval() or lastval() after the insert to the get the value of the sequence directly:
insert into some_table (..)
values (...);
select lastval();
The usage of lastval() requires that no other value is generated by a different sequence between the INSERT and the SELECT. If you can't guarantee that, use currval() and specify the name of the sequence:
insert into some_table (...)
values (...);
select currval('some_table_company_id_seq');
If you want to avoid hardcoding the sequence name, use pg_get_serial_sequence()
select currval(pg_get_serial_sequence('some_table', 'company_id'));

Rollback doesn't work with Amazon Redshift

I am practicing with redshift, I have created a table:
Inserted values from another table
Delete the data from table
I have tried rollback both of this steps, but it doesn't work. What is wrong with this, I don't understand?
Open two psql terminals connected to same Redshift intance and database, say terminal-1 and terminal-2.
Execute following queries on terminal-1.
create table sales(
salesid integer not null Identity,
commission decimal(8,2),
saledate date,
description varchar(255),
created_at timestamp default sysdate,
updated_at timestamp);
begin;
insert into sales(commission,saledate,description,created_at,updated_at) values('3.55','2018-12-10','Test description','2018-05-17 23:54:51','2018-05-17 23:54:51');
insert into sales(commission,saledate,description,created_at,updated_at) values('5.67','2018-11-10','Test description1','2018-05-17 23:54:51','2018-05-17 23:54:51');
Hold on here and go to terminal-2; don't close the terminal-1, and execute following query
select * from sales;
You will not get above two data records inserted from terminal-1.
Hold on here, again go to terminal-1; and execute below query.
commit;
Hold on here and go to terminal-2; execute following query again
select * from sales;
Now, you will both records.
Point proven.

Getting the primary key after row insertion using redshift

I'm using postgresql 8.0.2 with amazon redshift and I'm trying to set up a INSERT command that also returns the PRIMARY KEY.
I was originally trying to do the following:
with get_connection() as conn:
with conn.cursor() as cur:
cur.execute('INSERT INTO orders (my_id, my_amount) \
VALUES (%s, %s) RETURNING row_id;', (some_id, some_amount))
conn.commit()
However, the RETURNING command only works on postgresql 8.2 and above.
I saw that currval might be a possible way to get this to work, but I read that it requires a sequence object.
I'm trying to insert the following schema
CREATE SEQUENCE order_seq;
CREATE TABLE IF NOT EXISTS orders
(
order_id INTEGER IDENTITY(1,1) PRIMARY KEY DISTKEY,
)
Then do:
with get_connection() as conn:
with conn.cursor() as cur:
cur.execute('INSERT INTO orders (my_id, my_amount) \
VALUES (%s, %s);', (some_id, some_amount))
conn.commit()
cur.execute('SELECT currval();')
row_id = cursor.fetchone()[0]
UPDATE: Sequence objects are not supported by redshift either. I feel like this is a pretty basic procedure but there is no easy way to get a reference to the current row.
Just define your column as:
order_id INTEGER PRIMARY KEY DISTKEY
And with your sequence created order_seq use this as insert command:
cur.execute('INSERT INTO orders (order_id, my_id, my_amount) \
VALUES (nextval(''order_seq''), %s, %s);', (some_id, some_amount))
Since you are using a sequence you have to add the field on the insert command to use the nextval properly.
And to retrieve current sequence value do as follow:
cur.execute('SELECT currval(''order_seq'')')
row_id = cursor.fetchone()[0]
I'm not familirized with the language you are using so you may have to change the syntaxe to scape the double quotes I use.
The syntaxe of nextval and currval is like: nextval('sequenceName') and currval('sequenceName')
So if it does not support sequences the only way I see that it could solve your issue is following this steps:
Open a transaction (so others wont get the same id)
fetch max id of your table like select max(order_id) from orders into a variable
use this value on the insert as it was the sequence.

INSERT INTO, return number of rows inserted [duplicate]

My database driver for PostgreSQL 8/9 does not return a count of records affected when executing INSERT or UPDATE.
PostgreSQL offers the non-standard syntax "RETURNING" which seems like a good workaround. But what might be the syntax? The example returns the ID of a record, but I need a count.
INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets')
RETURNING did;
I know this question is oooolllllld and my solution is arguably overly complex, but that's my favorite kind of solution!
Anyway, I had to do the same thing and got it working like this:
-- Get count from INSERT
WITH rows AS (
INSERT INTO distributors
(did, dname)
VALUES
(DEFAULT, 'XYZ Widgets'),
(DEFAULT, 'ABC Widgets')
RETURNING 1
)
SELECT count(*) FROM rows;
-- Get count from UPDATE
WITH rows AS (
UPDATE distributors
SET dname = 'JKL Widgets'
WHERE did <= 10
RETURNING 1
)
SELECT count(*) FROM rows;
One of these days I really have to get around to writing a love sonnet to PostgreSQL's WITH clause ...
I agree w/ Milen, your driver should do this for you. What driver are you using and for what language? But if you are using plpgsql, you can use GET DIAGNOSTICS my_var = ROW_COUNT;
http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS
You can take ROW_COUNT after update or insert with this code:
insert into distributors (did, dname) values (DEFAULT, 'XYZ Widgets');
get diagnostics v_cnt = row_count;
It's not clear from your question how you're calling the statement. Assuming you're using something like JDBC you may be calling it as a query rather than an update. From JDBC's executeQuery:
Executes the given SQL statement, which returns a single ResultSet
object.
This is therefore appropriate when you execute a statement that returns some query results, such as SELECT or INSERT ... RETURNING. If you are making an update to the database and then want to know how many tuples were affected, you need to use executeUpdate which returns:
either (1) the row count for SQL Data Manipulation Language (DML)
statements or (2) 0 for SQL statements that return nothing
You could wrap your query in a transaction and it should show you the count before you ROLLBACK or COMMIT. Example:
BEGIN TRANSACTION;
INSERT .... ;
ROLLBACK TRANSACTION;
If you run the first 2 lines of the above, it should give you the count. You can then ROLLBACK (undo) the insert if you find that the number of affected lines isn't what you expected. If you're satisfied that the INSERT is correct, then you can run the same thing, but replace line 3 with COMMIT TRANSACTION;.
Important note: After you run any BEGIN TRANSACTION; you must either ROLLBACK; or COMMIT; the transaction, otherwise the transaction will create a lock that can slow down or even cripple an entire system, if you're running on a production environment.