Query
SELECT CASE WHEN name ILIKE 'THE %' -- simpler
THEN right(name, -4) || ', THE' -- simpler, faster
ELSE name END AS name -- but better use a distinct alias
, *
FROM artist
ORDER BY 1; -- positional reference to 1st output column
Rationale
The simplest and fastest expression to get a string minus n leading characters is: right(string, -n)
.
ILIKE
is simpler than lower()
/ upper() LIKE ...
.
You don't need concat()
, the plain concatenation operator ||
does the same faster since the expression right(name, -4)
is guaranteed to be NOT NULL
in this context.
When confused with SQL visibility rules for column names, or when there are duplicate output column names (which is totally legit in Postgres) you can also use positional references in GROUP BY
, ORDER BY
or DISTINCT ON (...)
clauses:
However, it's hardly wise or useful to have duplicate output column names in the first place. Rather use distinct names.
If you run this query a lot I suggest a functional index on the same expression for much faster results:
CREATE INDEX artist_name_sort_idx ON artist
((CASE WHEN name ILIKE 'THE %' THEN right(name, -4) || ', THE' ELSE name END));
The expression in the query must be the same to employ this index.
Proper test case
WITH artist(artist_id, name) AS (
VALUES
(1, 'The Beatles')
, (2, 'tHe bEatles')
, (3, 'The The')
, (4, 'Then')
, (5, 'The X')
, (6, 'Theodor')
, (7, 'Abba')
, (8, 'ZZ TOP')
, (9, 'The ') -- unlikely corner case, I don't think it would pay to test for it
, (10, '') -- empty string
, (11, NULL) -- NULL
)
SELECT CASE WHEN name ILIKE 'THE %' THEN right(name, -4) || ', THE' ELSE name END AS name
, *
FROM artist
ORDER BY 1;
Result:
name | artist_id | name
--------------+-----------+-------------
| 10 |
, THE | 9 | The -- remaining corner case
Abba | 7 | Abba
bEatles, THE | 2 | tHe bEatles
Beatles, THE | 1 | The Beatles
The, THE | 3 | The The
Then | 4 | Then
Theodor | 6 | Theodor
X, THE | 5 | The X
ZZ TOP | 8 | ZZ TOP
<NULL> | 11 | <NULL>