HiveBrain v1.2.0
Get Started
← Back to all entries
snippetsqlMinor

How do I simultaneously update unique keys in PostgreSQL?

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
postgresqluniqueupdatekeyssimultaneouslyhow

Problem

CREATE TABLE widget (
  id serial PRIMARY KEY,
  name text NOT NULL,
  ordinal int NOT NULL UNIQUE
);


I have the data

id | name | ordinal 
----+------+---------
  1 | A    |       1
  2 | B    |       2
  3 | C    |       3


I would like to update it to

id | name | ordinal 
----+------+---------
  1 | A    |       3
  2 | B    |       2
  3 | C    |       1


Touching records as little as possible (i.e. don't rewrite the entire record set, don't kick off unnecessary triggers), what's the generally applicable approach to updating ordinal to be the target values?

A vanilla update just gives me constraint violations, even if it happens in a single statement.

And dropping and recreating the unique constraint is expensive and poor concurrency.

This seems like a common enough problem that there ought to be a good way to do this, that I just can't think of.

Solution

Define the constraint as deferrable:

CREATE TABLE widget (
  id serial PRIMARY KEY,
  name text NOT NULL,
  ordinal int NOT NULL UNIQUE DEFERRABLE
);


Then you can update it in one statement:

update widget
  set ordinal = t.new_ordinal
from (
  values (1, 3), (3,1) 
) as t(id, new_ordinal)
where t.id = widget.id

Code Snippets

CREATE TABLE widget (
  id serial PRIMARY KEY,
  name text NOT NULL,
  ordinal int NOT NULL UNIQUE DEFERRABLE
);
update widget
  set ordinal = t.new_ordinal
from (
  values (1, 3), (3,1) 
) as t(id, new_ordinal)
where t.id = widget.id

Context

StackExchange Database Administrators Q#285910, answer score: 6

Revisions (0)

No revisions yet.