在Microsoft SQL Server中,可以指定“重音不敏感”排序规则(对于数据库,表或列),这意味着可以进行类似
的查询SELECT * FROM users WHERE name LIKE 'João'
找到名称为Joao
的行。
我知道可以使用unaccent_string contrib函数从PostgreSQL中删除字符串的重音,但我想知道PostgreSQL是否支持这些“重音不敏感”排序规则,因此上面的SELECT
可以正常工作。
答案 0 :(得分:168)
使用unaccent module - 这与您链接的内容完全不同。
unaccent是一个删除重音的文本搜索词典(变音符号 来自lexemes的迹象。
每个数据库安装一次:
CREATE EXTENSION unaccent;
如果收到如下错误:
错误:无法打开扩展控制文件 “/usr/share/postgresql/9.x/extension/unaccent.control”:没有这样的文件 或目录
在数据库服务器上安装contrib包,如相关答案中所述:
除此之外,它还提供了您可以在示例中使用的函数unaccent()
(其中似乎不需要LIKE
)。
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
要为此类查询使用索引,请创建index on the expression。 但是,Postgres只接受IMMUTABLE
索引函数。如果函数可以为同一输入返回不同的结果,则索引可能会静默地中断。
unaccent()
仅STABLE
而非IMMUTABLE
不幸的是,unaccent()
仅为STABLE
,而非IMMUTABLE
。根据{{3}},这是由于三个原因:
search_path
,它可以轻松改变。 this thread on pgsql-bugs指示将功能波动率改为IMMUTABLE
。这种强力方法在某些条件下会破裂。
其他人建议Some tutorials(就像我过去做过的那样)。
关于是否明确声明使用过的字典的simple IMMUTABLE
wrapper function IMMUTABLE
,一直存在争议。阅读variant with two parameters或here。
另一个替代方案是这个模块带有here,在Github上提供。没有自己测试过。我想我已经想出了 更好的主意 :
我提出的方法至少与其他解决方案一样有效,但更安全: 使用双参数形式创建包装函数,并使用“硬连线”函数和字典的模式:
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary
$func$ LANGUAGE sql IMMUTABLE;
public
是您安装扩展程序的架构(public
是默认设置)。
以前,我已将SET search_path = public, pg_temp
添加到函数中 - 直到我发现字典也可以是模式限定的IMMUTABLE unaccent()
function by Musicbrainz。在我的第9.5行和第10页的测试中,这个版本有点短,大约快两倍。
更新后的版本仍然不允许which is currently (pg 10) not documented,因为声明IMMUTABLE
的函数可能不会调用正文中的非不可变函数来允许它。当我们在IMMUTABLE
函数上使用 function inlining 时,对性能几乎无关紧要:
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
使用Postgres 10.3 / 9.6.8等来加强客户端程序的安全性。当需要来模式限定函数和字典时,如在任何索引中使用时所示。参见:
调整查询以匹配索引(以便查询计划程序可以使用它):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
您不需要正确表达式中的函数。您可以直接提供'Joao'
等非重音字符串。
在Postgres 9.5或更早中,必须手动扩展“Œ”或“ß”等连字(如果需要),因为unaccent()
始终替换单< / em>信:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
你会喜欢Postgres中的'text search dictionary “unaccent” does not exist' entries in postgres log, supposedly during automatic analyze 9.6 :
扩展
contrib/unaccent
的标准unaccent.rules
文件以处理所有问题 Unicode已知的变音符号,正确扩展连字(Thomas Munro,LéonardBenedetti)
大胆强调我的。现在我们得到:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
对于具有任意模式的 LIKE
或 ILIKE
,请将其与PostgreSQL 9.1或更高版本中的模块this update to unaccent结合使用。创建一个三元组GIN(通常是可取的)或GIST表达式索引。 GIN示例:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
可用于以下查询:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
GIN和GIST索引的维护成本比普通btree要贵:
对于左锚定模式,有更简单的解决方案。有关模式匹配和性能的更多信息:
pg_trgm
还提供了有用的Pattern matching with LIKE, SIMILAR TO or regular expressions in PostgreSQL。
Trigram索引还支持使用~
等的简单正则表达式。 不区分大小写的模式与ILIKE
匹配:
答案 1 :(得分:2)
我非常确定PostgreSQL依赖底层操作系统进行整理。它 支持creating new collations和customizing collations。不过,我不确定你可能会做多少工作。 (可能相当多。)
答案 2 :(得分:2)
PostgreSQL不支持这样的排序规则(重音不敏感或不重音),因为除非事物是二进制相等的,否则不能进行比较。这是因为在内部它会为哈希索引之类的东西带来很多复杂性。因此,最严格意义上的排序仅影响排序而非平等。
对于FTS,您可以使用unaccent
,
CREATE EXTENSION unaccent;
CREATE TEXT SEARCH CONFIGURATION mydict ( COPY = simple );
ALTER TEXT SEARCH CONFIGURATION mydict
ALTER MAPPING FOR hword, hword_part, word
WITH unaccent, simple;
然后您可以使用功能索引
进行索引-- Just some sample data...
CREATE TABLE myTable ( myCol )
AS VALUES ('fóó bar baz'),('qux quz');
-- No index required, but feel free to create one
CREATE INDEX ON myTable
USING GIST (to_tsvector('mydict', myCol));
您现在可以非常简单地查询
SELECT *
FROM myTable
WHERE to_tsvector('mydict', myCol) @@ 'foo & bar'
mycol
-------------
fóó bar baz
(1 row)
另见
unaccent
module也可以在没有FTS集成的情况下单独使用,用于结账Erwin's answer