6

I'm using Postgres. I have an old table and a new table. The records in the old table need to have related records in the new table. The new table records are effectively going to act as the parents for records in the new table.

I'm trying to write a migration where each "child" from the old table will have "parent" in the new table.

OLD TABLE (I've added a foreign key in anticipation of populating it as part of the migration)

 id | name | new_id (FK)
----+------+-------------
  1 | 1st  | 
  2 | 2nd  |

NEW TABLE

 id | name 
----+------
    |

I need to do the following:

  • SELECT all records from the old table
  • INSERT a record into the new table for each old record and RETURNING id
  • UPDATE the old record's foreign key value with the RETURNING id

Is there a way to accomplish this using a set query? Or do I need to start delving into Postgres specific things like LOOPs?

4
  • You can do this in Postgres. The question would be much easier to follow with sample data and results. Commented Apr 10, 2018 at 22:06
  • currval() if you know sequence name, lastval() for last insert in sequence, to alternate between select/insert/update in each loop for original rows, or RETURNING id method. Commented Apr 10, 2018 at 22:08
  • @GordonLinoff I've added some simplified table schemas. Commented Apr 10, 2018 at 22:19
  • I'm not too great with Postgres, but I wanted to do some research. This page should help you greatly. stackoverflow.com/questions/23382865/… Commented Apr 10, 2018 at 22:29

3 Answers 3

6

You can use a writable cte as follows:

--open transaction
BEGIN;

--avoid concurrent writes
LOCK old_table IN ROW SHARE MODE;
LOCK new_table IN ROW SHARE MODE;

--create a sequence to populate new_table.id
CREATE SEQUENCE new_table_seq;

--using a writable cte to do the dirty job
WITH old_table_cte AS (
    UPDATE old_table SET new_id = nextval('new_table_seq') RETURNING *
)
INSERT INTO new_table SELECT new_id, name FROM old_table_cte;

--Create a proper FK
ALTER TABLE old_table ADD CONSTRAINT old_table_new_table_fk FOREIGN KEY (new_id) REFERENCES new_table (id);

--end transaction
COMMIT;

This approach has some benefits:

  • Taking advantage of RETURNING as you asked, but in update step. Avoiding an unnecessary extra SELECT;
  • Concurrency safe;
  • Postponing FK creation will result in a faster script;
  • Using pure SQL solution, no need to use procedural language;
  • Avoiding read and write to old_table at same step.
Sign up to request clarification or add additional context in comments.

Comments

0

This page should help you out :) postgreSQL function for last inserted ID

INSERT INTO tableName (column1, column2) VALUES ('column1val', 'column2val') RETURNING id;

You can then use the returned id to update the original row. You can also use a few other methods suggested on that SO page (mentioned below / linked above)

currval() if you know sequence name, lastval() for last insert in sequence, to alternate between select/insert/update in each loop for original rows, or RETURNING id method.

2 Comments

I know about RETURNING id but I need to do this for every record in my old table. It's how I should iterate over the records in the old table that I'm stumped on.
You need to use sequences to do what you want to do with Postgresql
-1

Use TEMP Table to perform migration. Before update on main table, we should manipulate data over TEMP table as requirement.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.