Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7787125
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 1, 20262026-06-01T20:33:48+00:00 2026-06-01T20:33:48+00:00

I have to migrate a large amount of existing data in a Postgres DB

  • 0

I have to migrate a large amount of existing data in a Postgres DB after a schema change.

In the old schema a country attribute would be stored in the users table. Now the country attribute has been moved into a separate address table:

users:
  country # OLD
  address_id # NEW [1:1 relation]

addresses:
  id
  country

The schema is actually more complex and the address contains more than just the country. Thus, every user needs to have his own address (1:1 relation).

When migrating the data, I’m having problems setting the foreign keys in the users table after inserting the addresses:

INSERT INTO addresses (country) 
    SELECT country FROM users WHERE address_id IS NULL 
    RETURNING id;

How do I propagate the IDs of the inserted rows and set the foreign key references in the users table?

The only solution I could come up with so far is creating a temporary user_id column in the addresses table and then updating the the address_id:

UPDATE users SET address_id = a.id FROM addresses AS a 
    WHERE users.id = a.user_id;

However, this turned out to be extremely slow (despite using indices on both users.id and addresses.user_id).

The users table contains about 3 million rows with 300k missing an associated address.

Is there any other way to insert derived data into one table and setting the foreign key reference to the inserted data in the other (without changing the schema itself)?

I’m using Postgres 8.3.14.

Thanks

I have now solved the problem by migrating the data with a Python/sqlalchemy script. It turned out to be much easier (for me) than trying the same with SQL. Still, I’d be interested if anybody knows a way to process the RETURNING result of an INSERT statement in Postgres SQL.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-01T20:33:49+00:00Added an answer on June 1, 2026 at 8:33 pm

    The table users must have some primary key that you did not disclose. For the purpose of this answer I will name it users_id.

    You can solve this rather elegantly with data-modifying CTEs introduced with PostgreSQL 9.1:

    country is unique

    The whole operation is rather trivial in this case:

    WITH i AS (
        INSERT INTO addresses (country) 
        SELECT country
        FROM   users
        WHERE  address_id IS NULL 
        RETURNING id, country
        )
    UPDATE users u
    SET    address_id = i.id
    FROM   i
    WHERE  i.country = u.country;
    

    You mention version 8.3 in your question. Upgrade! Postgres 8.3 has reached end of life.

    Be that as it may, this is simple enough with version 8.3. You just need two statements:

    INSERT INTO addresses (country) 
    SELECT country
    FROM   users
    WHERE  address_id IS NULL;
    
    UPDATE users u
    SET    address_id = a.id
    FROM   addresses a
    WHERE  address_id IS NULL 
    AND    a.country = u.country;
    

    country is not unique

    That’s more challenging. You could just create one address and link to it multiple times. But you did mention a 1:1 relationship that rules out such a convenient solution.

    WITH s AS (
        SELECT users_id, country
             , row_number() OVER (PARTITION BY country) AS rn
        FROM   users
        WHERE  address_id IS NULL 
        )
        , i AS (
        INSERT INTO addresses (country) 
        SELECT country
        FROM   s
        RETURNING id, country
        )
        , r AS (
        SELECT *
             , row_number() OVER (PARTITION BY country) AS rn
        FROM   i
        )
    UPDATE users u
    SET    address_id = r.id
    FROM   r
    JOIN   s USING (country, rn)    -- select exactly one id for every user
    WHERE  u.users_id = s.users_id
    AND    u.address_id IS NULL;
    

    As there is no way to unambiguously assign exactly one id returned from the INSERT to every user in a set with identical country, I use the window function row_number() to make them unique.

    Not as straight forward with Postgres 8.3. One possible way:

    INSERT INTO addresses (country) 
    SELECT DISTINCT country -- pick just one per set of dupes
    FROM   users
    WHERE  address_id IS NULL;
    
    UPDATE users u
    SET    address_id = a.id
    FROM   addresses a
    WHERE  a.country = u.country
    AND    u.address_id IS NULL
    AND NOT EXISTS (
        SELECT * FROM addresses b
        WHERE  b.country = a.country
        AND    b.users_id < a.users_id
        ); -- effectively picking the smallest users_id per set of dupes
    

    Repeat this until the last NULL value is gone from users.address_id.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

We have developed a large data migration from one DB schema to the other.
I currently have a daily process that loads a large amount of data from
I have to migrate a very large dataset from one system to another. One
The problem is: I have 3 mongo tables, and I want to migrate data
I have been asked to migrate a schema from our testing area into our
Problem: I have a large Visual C++ project that I'm trying to migrate to
We have a fairly large SVN repository which we are looking to migrate to
I need to migrate data in a large flat table located in SQL Server
I am in the process of migrating a large amount of data from several
I have a bit old project that I would call legacy. Some characteristics of

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.