PostgreSQL - insert rows based on select from another table, and update an FK in that table with the newly inserted rows

Carl Meyer

I am doing a data migration between two tables (splitting out a related table). The existing table is reminders, and it has a start column and a newly-added dateset_id column pointing to a new dateset table, which also has a start column. For every row in reminders, I want to INSERT a new row in dateset with the start value copied over, and UPDATE the corresponding row in reminders with the newly-inserted dateset ID.

Here's the SQL I tried:

WITH inserted_datesets AS (
  INSERT INTO dateset (start)
  SELECT start FROM reminder
  RETURNING reminder.id AS reminder_id, id AS dateset_id
)
UPDATE reminder
SET dateset_id = ids.dateset_id
FROM inserted_datesets AS ids
WHERE reminder.id = ids.reminder_id

I get an error missing FROM-clause entry for table "reminder", because I'm including the reminder.id column in the RETURNING clause, but not actually selecting it for the insert. This makes sense, but I can't figure out how to modify the query to do what I need. Is there a totally different approach I'm missing?

Vladimir Baranov

There are several ways to solve the problem.

1. temporarily add a column

As others mentioned, the straight-forward way is to temporarily add a column reminder_id to the dateset. Populate it with original IDs from reminder table. Use it to join reminder with the dateset table. Drop the temporary column.

2. when start is unique

If values of the start column is unique it is possible to do it without extra column by joining reminder table with the dateset table on the start column.

INSERT INTO dateset (start)
SELECT start FROM reminder;

WITH
CTE_Joined
AS
(
    SELECT
        reminder.id AS reminder_id
        ,reminder.dateset_id AS old_dateset_id
        ,dateset.id AS new_dateset_id
    FROM
        reminder
        INNER JOIN dateset ON dateset.start = reminder.start
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

3. when start is not unique

It is possible to do it without temporary column even in this case. The main idea is the following. Let's have a look at this example:

We have two rows in reminder with the same start value and IDs 3 and 7:

reminder
id    start         dateset_id
3     2015-01-01    NULL
7     2015-01-01    NULL

After we insert them into the dateset, there will be new IDs generated, for example, 1 and 2:

dateset
id    start
1     2015-01-01
2     2015-01-01

It doesn't really matter how we link these two rows. The end result could be

reminder
id    start         dateset_id
3     2015-01-01    1
7     2015-01-01    2

or

reminder
id    start         dateset_id
3     2015-01-01    2
7     2015-01-01    1

Both of these variants are correct. Which brings us to the following solution.

Simply insert all rows first.

INSERT INTO dateset (start)
SELECT start FROM reminder;

Match/join two tables on start column knowing that it is not unique. "Make it" unique by adding ROW_NUMBER and joining by two columns. It is possible to make the query shorter, but I spelled out each step explicitly:

WITH
CTE_reminder_rn
AS
(
    SELECT
        id
        ,start
        ,dateset_id
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM reminder
)
,CTE_dateset_rn
AS
(
    SELECT
        id
        ,start
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM dateset
)
,CTE_Joined
AS
(
    SELECT
        CTE_reminder_rn.id AS reminder_id
        ,CTE_reminder_rn.dateset_id AS old_dateset_id
        ,CTE_dateset_rn.id AS new_dateset_id
    FROM
        CTE_reminder_rn
        INNER JOIN CTE_dateset_rn ON 
            CTE_dateset_rn.start = CTE_reminder_rn.start AND
            CTE_dateset_rn.rn = CTE_reminder_rn.rn
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

I hope it is clear from the code what it does, especially when you compare it to the simpler version without ROW_NUMBER. Obviously, the complex solution will work even if start is unique, but it is not as efficient, as a simple solution.

This solution assumes that dateset is empty before this process.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Insert multiple rows from select into another table

From Dev

Update, Insert and Delete rows in a table based on changes in another table

From Dev

select rows from table based on data from another table

From Dev

select rows from table based on data from another table

From Dev

sql insert rows from another table based on condition

From Dev

sql insert rows from another table based on condition

From Dev

INSERT rows multiple times based on a column value from another table

From Dev

select multiple column from one table and insert into another as rows

From Dev

Select rows conditionally and insert into another table conditionally

From Dev

Laravel select random rows from table based on another field

From Dev

How to insert rows in another table based on insert in first table

From Dev

How to update rows in a table based on a range from two rows in another table

From Dev

Linq Update a row if new rows are inserted in another table

From Dev

Select rows from one table and adjust the values based on rows in another table

From Dev

Select rows with show flag but based on another table

From Dev

MySQL: Update rows in table, from rows with matching key in another table

From Dev

Select rows not in another table

From Dev

Request: Update or Insert rows from the same table

From Dev

insert multiple rows mysql from another table

From Dev

PostgreSQL: deleting rows referenced from another table

From Dev

Insert multiple rows in one table based on number in another table

From Dev

Unable to filter rows of one table based on data in another table in PostgreSQL

From Dev

Delete sql rows with fk in another table

From Dev

MYSQL - UPDATE multiple rows from another table

From Dev

Update specific rows from one table to another

From Dev

PLSQL UPDATE BASED ON ROWS FROM OTHER TABLE

From Dev

mysql: select rows from another table as columns

From Dev

Insert a group of rows to a table in PostgreSQL

From Dev

Select multiple rows from table based on ID

Related Related

  1. 1

    Insert multiple rows from select into another table

  2. 2

    Update, Insert and Delete rows in a table based on changes in another table

  3. 3

    select rows from table based on data from another table

  4. 4

    select rows from table based on data from another table

  5. 5

    sql insert rows from another table based on condition

  6. 6

    sql insert rows from another table based on condition

  7. 7

    INSERT rows multiple times based on a column value from another table

  8. 8

    select multiple column from one table and insert into another as rows

  9. 9

    Select rows conditionally and insert into another table conditionally

  10. 10

    Laravel select random rows from table based on another field

  11. 11

    How to insert rows in another table based on insert in first table

  12. 12

    How to update rows in a table based on a range from two rows in another table

  13. 13

    Linq Update a row if new rows are inserted in another table

  14. 14

    Select rows from one table and adjust the values based on rows in another table

  15. 15

    Select rows with show flag but based on another table

  16. 16

    MySQL: Update rows in table, from rows with matching key in another table

  17. 17

    Select rows not in another table

  18. 18

    Request: Update or Insert rows from the same table

  19. 19

    insert multiple rows mysql from another table

  20. 20

    PostgreSQL: deleting rows referenced from another table

  21. 21

    Insert multiple rows in one table based on number in another table

  22. 22

    Unable to filter rows of one table based on data in another table in PostgreSQL

  23. 23

    Delete sql rows with fk in another table

  24. 24

    MYSQL - UPDATE multiple rows from another table

  25. 25

    Update specific rows from one table to another

  26. 26

    PLSQL UPDATE BASED ON ROWS FROM OTHER TABLE

  27. 27

    mysql: select rows from another table as columns

  28. 28

    Insert a group of rows to a table in PostgreSQL

  29. 29

    Select multiple rows from table based on ID

HotTag

Archive