PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Wstawiaj dane i ustawiaj klucze obce za pomocą Postgres

Tabela users musi mieć jakiś klucz podstawowy czego nie ujawniłeś. Na potrzeby tej odpowiedzi nazwę ją users_id .

Możesz rozwiązać to dość elegancko dzięki modyfikującym dane CTE wprowadzony z PostgreSQL 9.1 :

country jest wyjątkowy

Cała operacja jest w tym przypadku dość banalna:

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;

Wspominasz wersję 8.3 w twoim pytaniu. Uaktualnić! Postgres 8.3 dobiegł końca.

Tak czy inaczej, jest to dość proste w wersji 8.3. Potrzebujesz tylko dwóch stwierdzeń:

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 nie jest wyjątkowy

To jest większe wyzwanie. możesz po prostu utwórz jeden adres i łącz do niego wiele razy. Ale wspomniałeś o relacji 1:1, która wyklucza tak wygodne rozwiązanie.

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;

Ponieważ nie ma możliwości jednoznacznego przypisania dokładnie jednego id zwrócone z INSERT do każdego użytkownika w zestawie z identycznym country , używam funkcji okna row_number() aby uczynić je wyjątkowymi.

Nie tak prosto z Postgresem 8.3 . Jeden możliwy sposób:

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

Powtórz to do ostatniego NULL wartość zniknęła z users.address_id .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Połączenie odrzucone (PGError) (postgresql i rails)

  2. Konfigurowanie klucza obcego z innym typem danych

  3. BŁĄD:odmowa uprawnień dla schematu user1_gmail_com o znaku 46

  4. Uzyskaj liczbę dni w miesiącu w PostgreSQL

  5. Jak uzyskać PostgreSQL na serwerze VPS/serwerze dedykowanym?