SELECT * FROM users WHERE name LIKE 'João'
找到具有Joao名称的行。
我知道,可以使用unaccent_string contrib函数从Postgresql中的字符串剥离重音,但我想知道Postgresql是否支持这些“重音不敏感”的排序规则,所以上面的SELECT将工作。
unaccent is a text search dictionary that removes accents (diacritic
signs) from lexemes.
每个数据库安装一次:
CREATE EXTENSION unaccent;
如果你得到一个错误,如:
ERROR: could not open extension control file
“/usr/share/postgresql/9.x/extension/unaccent.control”: No such file
or directory
在数据库服务器上安装contrib包,就像在这个相关的答案中所说的:
> Error when creating unaccent extension on PostgreSQL
除此之外,它还提供了可以与您的示例(其中LIKE似乎不需要)一起使用的函数unaccent()。
SELECT * FROM users WHERE unaccent(name) = unaccent('João');
指数
要为这种查询使用索引,请创建一个index on the expression.但是,Postgres仅接受索引的IMMUTABLE函数。如果一个函数可以为同一个输入返回不同的结果,那么索引可能会无声地断开。
unaccent()只有STABLE不是IMMUTABLE
不幸的是,unaccent()只是STABLE,而不是IMMUTABLE。根据this thread on pgsql-bugs,这是由于三个原因:
>它取决于字典的行为。
>没有到这个字典的硬接线连接。
>因此它也取决于当前的search_path,它可以很容易改变。
Some tutorials在web上指示只是将函数的易变性改为IMMUTABLE。这种强力方法在某些情况下可能会中断。
其他人建议一个simple IMMUTABLE
wrapper function – 像我自己在过去。
有一个持续的争论是否使明确声明使用的字典的variant with two parameters IMMUTABLE。阅读here或here。
另一个选择是这个模块与一个IMMUTABLE unaccent()
function by Musicbrainz,提供Github。没有自己测试。我想我已经提出了一个更好的主意:
最好的
我提出一种方法,至少与其他解决方案一样有效,但更安全:
创建一个包含两个参数形式的包装器函数,并为函数和字典“硬连线”模式:
CREATE OR REPLACE FUNCTION f_unaccent(text) RETURNS text AS $func$ SELECT public.unaccent('public.unaccent',$1) -- schema-qualify function and dictionary $func$ LANGUAGE sql IMMUTABLE;
public是您安装扩展的模式(public是默认值)。
更新02.2016:以前,我添加了SET search_path = public,pg_temp到函数 – 直到我发现字典也可以是模式限定的,which is currently not documented.这个版本有点更短,是我在pg上的测试的两倍9.5并允许 function inlining。
你可以在这个IMMUTABLE函数上建立一个expression index:
CREATE INDEX users_unaccent_name_idx ON users(f_unaccent(name));
调整您的查询以使用索引:
SELECT * FROM users WHERE f_unaccent(name) = f_unaccent('João');
你不需要在正确的表达式中的函数。你可以直接提供不重要的字符串,如“Joao”。
连字
在Postgres 9.5或更高版本中,我们需要手动(如果我们需要)展开连字,如“Œ”或“ß”,因为unaccent()总是替换一个字母:
SELECT unaccent('Œ Æ œ æ ß'); unaccent ---------- E A e a S
你会爱上this update to unaccent在Postgres 9.6:
Extend
contrib/unaccent
‘s standardunaccent.rules
file to handle all
diacritics known to Unicode,and expand ligatures correctly (Thomas
Munro,Léonard Benedetti)
大胆强调我。现在我们得到:
SELECT unaccent('Œ Æ œ æ ß'); unaccent ---------- OE AE oe ae ss
模式匹配
对于具有任意模式的LIKE或ILIKE,将其与Postgresql 9.1或更高版本中的模块pg_tgrm
组合。创建GIN(优选)或GIST表达式索引。 GIN的示例:
CREATE INDEX users_unaccent_name_trgm_idx ON users USING gin (f_unaccent(name) gin_trgm_ops);
GIN and GIST indexes are more expensive to maintain.此索引可用于以下查询:
SELECT * FROM users WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
对于刚刚左边锚定的模式有更简单的解决方案。更多关于模式匹配和性能:
> Pattern matching with LIKE,SIMILAR TO or regular expressions in PostgreSQL
pg_tgrm还提供了useful operators for “similarity” %
and “distance” <->
。
Trigram索引也支持简单的正则表达式〜〜。和与ILIKE的不区分大小写模式匹配: