Postgres обновить столбец, при конфликте игнорировать эту строку - PullRequest
1 голос
/ 15 апреля 2020

У меня есть таблица с email и secondary_email. Столбец email имеет уникальное ограничение, в то время как secondary_email может повторяться по строкам.

Мне нужно написать запрос для копирования secondary_email в email. Если есть конфликт, игнорируйте эту строку.

Этот запрос

UPDATE users SET email = secondary_email
WHERE NOT EXISTS
(SELECT 1 FROM users WHERE email=secondary_email)

все еще выдает ошибку ERROR: duplicate key value violates unique constraint "users_email_key"

Пользователи до

+----+-------+-----------------+
| id | email | secondary_email |
+----+-------+-----------------+
| 1  | NULL  | NULL            |
| 2  | NULL  | NULL            |
| 3  | NULL  |                 |
| 4  | NULL  | e1@example.com  |
| 5  | NULL  | e1@example.com  |
| 6  | NULL  | e2@example.com  |
+----+-------+-----------------+

Пользователи после

+----+----------------+-----------------+
| id | email          | secondary_email |
+----+----------------+-----------------+
| 1  | NULL           | NULL            |
| 2  | NULL           | NULL            |
| 3  | NULL           |                 |
| 4  | e1@example.com | e1@example.com  |
| 5  | NULL           | e1@example.com  |
| 6  | e2@example.com | e2@example.com  |
+----+----------------+-----------------+

1 Ответ

1 голос
/ 15 апреля 2020

Вам нужны псевдонимы таблиц, чтобы исправить ваш запрос:

UPDATE users u
    SET email = u.secondary_email
    WHERE NOT EXISTS (SELECT 1 FROM users u2 WHERE u2.email = u.secondary_email);

Для вашей общей проблемы проверьте также, нет ли дубликатов в столбце:

UPDATE users u
    SET email = u.secondary_email
    FROM (SELECT secondary_email, COUNT(*) as cnt
          FROM users u
          GROUP BY secondary_email
          HAVING COUNT(*) = 1
         ) s
    WHERE s.secondary_email = u.secondary_email AND
          NOT EXISTS (SELECT 1 FROM users u2 WHERE u2.email = u.secondary_email);

Или выберите первый :

UPDATE users u
    SET email = u.secondary_email
    FROM (SELECT u.*,
                 ROW_NUMBER() OVER (PARTITION BY secondary_email ORDER BY user_id) as seqnum
          FROM users u
         ) s
    WHERE s.user_id = u.user_id AND
          s.seqnum = 1 AND
          NOT EXISTS (SELECT 1 FROM users u2 WHERE u2.email = u.secondary_email);

Примечание: Это также отфильтрует значения NULL, что кажется хорошей идеей.

Здесь - это дб <> скрипка.

...