sql >> Databáze >  >> RDS >> PostgreSQL

Vložte data a nastavte cizí klíče pomocí Postgres

Tabulka users musí mít nějaký primární klíč které jste neprozradil. Pro účely této odpovědi ji pojmenuji users_id .

Můžete to poměrně elegantně vyřešit pomocí úprav dat CTE představeno s PostgreSQL 9.1 :

country je unikátní

Celá operace je v tomto případě poněkud triviální:

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;

Zmiňujete verzi 8.3 ve vaší otázce. Vylepšit! Postgres 8.3 dosáhl konce životnosti.

Ať je to jak chce, s verzí 8.3 je to dostatečně jednoduché. Potřebujete pouze dvě prohlášení:

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 není jedinečný

To je náročnější. Mohli byste stačí vytvořit jednu adresu a několikrát na ni odkazovat. Ale zmínil jste vztah 1:1, který vylučuje takové pohodlné řešení.

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;

Protože neexistuje způsob, jak jednoznačně přiřadit právě jedno id vrácené z INSERT každému uživateli v sadě s identickou country , používám funkci okna row_number() aby byly jedinečné.

Ne tak přímočaré s Postgres 8.3 . Jeden možný způsob:

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

Opakujte to až do posledního NULL hodnota je pryč z users.address_id .




  1. Část 3 – Zákazníci, hovory a schůzky

  2. Oracle dynamic DESC a ASC v pořadí podle

  3. postgresql - počet (žádné hodnoty null) každého sloupce v tabulce

  4. Dotaz MySQL – záznamy mezi dneškem a posledními 30 dny