PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Daten einfügen und Fremdschlüssel mit Postgres setzen

Die Tabelle users muss einen Primärschlüssel haben die du nicht preisgegeben hast. Für diese Antwort nenne ich sie users_id .

Das können Sie recht elegant mit datenmodifizierenden CTEs lösen eingeführt mit PostgreSQL 9.1 :

country ist einzigartig

Die ganze Operation ist in diesem Fall ziemlich trivial:

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;

Sie erwähnen Version 8.3 in deiner frage. Aktualisierung! Postgres 8.3 hat das Lebensende erreicht.

Wie dem auch sei, mit der Version 8.3 ist dies einfach genug. Sie brauchen nur zwei Anweisungen:

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 ist nicht eindeutig

Das ist anspruchsvoller. Sie könnten Erstellen Sie einfach eine Adresse und verlinken Sie sie mehrmals. Aber Sie haben eine 1:1-Beziehung erwähnt, die eine so bequeme Lösung ausschließt.

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;

Denn es gibt keine Möglichkeit, genau eine id eindeutig zuzuordnen zurückgegeben von INSERT an jeden Benutzer in einem Set mit identischem country , verwende ich die Fensterfunktion row_number() um sie einzigartig zu machen.

Nicht so einfach mit Postgres 8.3 . Ein möglicher Weg:

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

Wiederholen Sie dies bis zum letzten NULL Wert ist aus users.address_id verschwunden .