Try PostgreSQL's citext

postgresql
Posted on: 2024-11-01

The PostgreSQL citext type (docs here) is a good choice for lots of user-facing text.

It stores the text with the case given, but for comparisons it ignores case.

You probably want searches to be case insensitive; eg, searching for "alex" should match "Alex". citext means you don't have to remember to convert the search term and column value to lowercase when searching.

Also, if you want to sort names alphabetically, you probably want Banana to come after apple, even though upper case Latin characters have smaller codepoint values than lower case ones (see the decimal set in man ascii). Since sorting involves comparison, citext takes care of this.

And if you have a unique index, you probably don't want to allow both foo@example.com and Foo@example.com. Again, since unique indexes involve comparison, citext means these values conflict.

Note that citext is an extension; you have to CREATE EXTENSION IF NOT EXISTS citext in order to use it.

Here are a few quick demos.

Ordering

WITH test_data(name) AS (
    VALUES
        ('Banana'),
        ('APE'),
        ('apple')
)
SELECT name FROM test_data ORDER BY name ASC;

  name
--------
 APE
 Banana
 apple
(3 rows)

vs

WITH test_data(name) AS (
    VALUES
        ('Banana'::citext),
        ('APE'::citext),
        ('apple'::citext)
)
SELECT name FROM test_data ORDER BY name ASC;

  name
--------
 APE
 apple
 Banana
(3 rows)

Uniqueness

WITH test_data(name) AS (
    VALUES
        ('Apple'),
        ('apple'),
        ('APPLE')
)
SELECT DISTINCT name FROM test_data;

 name
-------
 APPLE
 apple
 Apple
(3 rows)

vs

WITH test_data(name) AS (
    VALUES
        ('Apple'::citext),
        ('apple'::citext),
        ('APPLE'::citext)
)
SELECT DISTINCT name FROM test_data;

 name
-------
 Apple
(1 row)