我有一个表artist
,其中包含多个列,例如name
,type
...
我希望按字母顺序返回和排序列name
,但应调整列名称。如果艺术家的名称以' (不区分大小写)开头,则应将其删除并以大写形式放在名称后面,例如'甲壳虫乐队' - > ' Beatles,THE' 。
这是我的代码(它没有用):
SELECT name,
CASE
WHEN UPPER(name) LIKE 'THE %' THEN CONCAT(RIGHT(name, length(name)-4),', THE')
END AS name
FROM artist
ORDER BY name
问题1:name
未被替换,它会创建一个新列。
问题2:新列具有相同的名称=>列name
在order by name
中不明确。
如何轻松解决这些问题?
答案 0 :(得分:1)
在ELSE
中使用CASE
子句:
SELECT
CASE
WHEN UPPER(name) LIKE 'THE %' THEN CONCAT(RIGHT(name, length(name)-4),', THE')
ELSE name
END AS name
FROM artist
ORDER BY name
答案 1 :(得分:0)
如果您只想要这个用于排序,那么您只能将逻辑放在order by
子句中:
order by (case when name ilike 'the%'
then substring(name from 5) || ', The'
else name
end)
如果您还想在select
子句中使用此列,请使用name
以外的别名。这已经用于您的第一栏:
select name,
(case when name ilike 'the%'
then substring(name from 5) || ', The'
else name
end) as munged_name
. . .
order by munged_name
注意:ilike
是不区分大小写的like
的Postgres扩展。
答案 2 :(得分:0)
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
获取字符串减去 n个前导字符的最简单,最快的表达式为:right(string, -n)
。
ILIKE
比lower()
/ upper() LIKE ...
更简单。
您不需要concat()
,普通连接运算符||
的表达速度相同,因为表达式right(name, -4)
保证为{ {1}}在此背景下。
如果与列名的SQL可见性规则混淆,或者存在重复的输出列名(这在Postgres中完全合法),您还可以使用位置引用 NOT NULL
,GROUP BY
或ORDER BY
条款:
但是,首先拥有重复的输出列名称并不明智或有用。而是使用不同的名称。
如果您经常运行此查询,我建议在同一个表达式上使用functional index,以获得更快的结果:
DISTINCT ON (...)
查询中的表达式必须与使用此索引相同。
CREATE INDEX artist_name_sort_idx ON artist
((CASE WHEN name ILIKE 'THE %' THEN right(name, -4) || ', THE' ELSE name END));
结果:
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;