AWS Redshift - ILIKE 不适用于带重音的单词

AWS Redshift - ILIKE doesn't work with accented words

我们使用 AWS Redshift 已经有一段时间了,最​​近我们遇到了一个非常有趣的情况。

假设我们有以下 table.

CREATE TEMPORARY TABLE cities (city VARCHAR(256), state VARCHAR(256));

以及以下示例数据

INSERT INTO cities (city, state) VALUES 
('Campos do Jordão', 'São Paulo'),
('CAMPOS DO JORDÃO', 'SÃO Paulo'),
('campos do jordão', 'são paulo'),
('Balneário Camburiú', 'Santa Catarina'),
('balneÁrio camburiú', 'Santa Catarina'),
('BALNEÁRIO camburiÚ', 'Santa Catarina'),
('Açailândia', 'Maranhão'),
('AÇailândia', 'Maranhão'),
('AÇAILÂNDIA', 'Maranhão'),
('Salvador', 'Bahia'),
('SALvADOR', 'BAHIA'),
('salVAdor', 'BAHiA')
;

我们要筛选与特定城市对应的所有行。考虑到数据没有通过验证过程,所以同一个城市名称有多种不同的写法。

我们尝试使用ILIKE,比如SELECT * FROM cities WHERE city ILIKE 'Campos do Jordão',但是结果如下

city state
Campos do Jordão São Paulo
campos do jordão são paulo

我们得到了两条记录,而不是三条。经过一些测试,我们发现问题是由重音字符引起的(例如ãçá)。例如查询

SELECT * FROM cities WHERE city ILIKE '%Ú%';

returns只有记录('BALNEÁRIO camburiÚ', 'Santa Catarina'),而如果我们用%ú%.[=26替换%Ú%,同样的查询returns另外两条记录=]

我认为发生这种情况是因为 Redshift 将这些重音字符视为特殊字符,但最初当我们使用 UPPER 时它按预期工作。例如,下面的查询返回了 Balneário Camburiú.

的所有三个记录
SELECT * FROM cities WHERE UPPER(city) ILIKE '%Ú%';

我在这里发布这个例子是为了询问我是否遗漏了 ILIKE 命令中的某些内容,或者这是否真的是某种错误。

https://docs.aws.amazon.com/redshift/latest/dg/r_patternmatching_condition_like.html

LIKE performs a case-sensitive pattern match. ILIKE performs a case-insensitive pattern match for single-byte UTF-8 (ASCII) characters. To perform a case-insensitive pattern match for multibyte characters, use the LOWER function on expression and pattern with a LIKE condition.

我认为问题出在 Redshift 实际上并不理解 Unicode。

Redshift 将您放入其中的任何位模式存储到 varchar 中,无论是否有效的 Unicode。

当它执行比较时,它执行的是逐字节比较,而不是逐字符比较。

我认为有一些 函数 可以理解 Unicode,例如 upper()lower() - 它们是单独编写到主代码库中的。您必须了解 Unicode 才能更改多字节 UTF-8 字符的大小写;但是 LIKEILIKE 不是,它们是运算符,而不是函数,所以它们来自核心数据库代码库,不是 Unicode 识别。您必须使用 Unicode 识别函数为它们做一些工作,以允许它们正常运行。

顺便说一句,这也是一个引人入胜的问答。谢谢提问。