Таблицата users
трябва да има някакъв първичен ключ които не разкрихте. За целите на този отговор ще го кръстя users_id
.
Можете да решите това доста елегантно с CTE-промяна на данни въведен с PostgreSQL 9.1 :
country
е уникален
Цялата операция е доста тривиална в този случай:
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;
Споменавате версия 8.3 във вашия въпрос. Подобряване на! Postgres 8.3 достигна края на живота си.
Както и да е, това е достатъчно просто с версия 8.3. Трябват ви само две изявления:
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
не е уникален
Това е по-предизвикателно. Вие можете просто създайте един адрес и свързвайте към него няколко пъти. Но споменахте връзка 1:1, която изключва такова удобно решение.
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;
Тъй като няма начин недвусмислено да зададете точно един id
върнати от INSERT
на всеки потребител в набор с идентична country
, използвам функцията на прозореца row_number()
за да ги направите уникални.
Не толкова просто с Postgres 8.3 . Един възможен начин:
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
Повторете това до последния NULL
стойността е изчезнала от users.address_id
.