简体   繁体   中英

Postgres update column, on conflict ignore this row

I have a table with email and secondary_email . email column has a unique constraint, while secondary_email can be repeated across rows.

I have to write a query to copy secondary_email to email . If there is a conflict, then ignore this row.

This query

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

still throws the error ERROR: duplicate key value violates unique constraint "users_email_key"

Users Before

+----+-------+-----------------+
| 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  |
+----+-------+-----------------+

Users After

+----+----------------+-----------------+
| 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  |
+----+----------------+-----------------+

You need table aliases to fix your query:

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

For your overall problem, check for no duplicates within the column as well:

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);

Or choose the first one:

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);

Note: This will also filter out NULL values which seems like a good idea.

Here is a db<>fiddle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM