0

We have a UNIQUE constraint on a table to prevent our city_name and state_id combinations from being duplicated. The problem we have found is that accents circumvent this.

Example: "Montréal" "Quebec" and "Montreal" "Quebec"

We need a way to have the unique constraint run UNACCENT() and preferably wrap it in LOWER() as well for good measure. Is this possible?

Matt Weber
  • 2,808
  • 2
  • 14
  • 30
  • 1
    Probably the simplest way is to have two columns: first just to display which contains values like `"Montréal"` and second one for checks, indexing, searching, filtering etc which contains values like `"montreal"`... – Abelisto Jul 01 '20 at 07:41

2 Answers2

1

You can create an immutable version of unaccent:

CREATE FUNCTION noaccent(text) RETURNS text
   LANGUAGE sql IMMUTABLE STRICT AS
'SELECT unaccent(lower($1))';

and use that in a unique index on the column.

An alternative is to use a BEGORE INSERT OR UPDATE trigger that fills a new column with the unaccented value and put a unique constraint on that column.

Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
0

You can create unique indexes on expressions, see the Postgres manual:

https://www.postgresql.org/docs/9.3/indexes-expressional.html

So in your case it could be something like

CREATE UNIQUE INDEX idx_foo ON my_table ( UNACCENT(LOWER(city_name)), state_id )

Cody Caughlan
  • 32,456
  • 5
  • 63
  • 68