当str包含'é'或'ë'而substr仅包含'e'时,INSTR(str,substr)不起作用

时间:2014-01-04 15:58:23

标签: mysql utf-8 collation

在stackoverflow的另一篇文章中,我读到INSTR可用于按相关性排序结果。

我对col LIKE '%str%' and INSTR(col,'str')`的理解是它们的行为都相同。处理排序规则似乎有所不同。

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO users (name)
VALUES ('Joël'), ('René');

SELECT * FROM users WHERE name LIKE '%joel%'; -- 1 record returned
SELECT * FROM users WHERE name LIKE '%rene%'; -- 1 record returned
SELECT * FROM users WHERE INSTR(name, 'joel') > 0; -- 0 records returned
SELECT * FROM users WHERE INSTR(name, 'rene') > 0; -- 0 records returned
SELECT * FROM users WHERE INSTR(name, 'joël') > 0; -- 1 record returned
SELECT * FROM users WHERE INSTR(name, 'rené') > 0; -- 1 record returned

虽然INSTR进行了一些转换,但它会在ë中找到é

SELECT INSTR('é', 'ë'), INSTR('é', 'e'), INSTR('e', 'ë');
-- returns 1, 0, 0

我错过了什么吗?

http://sqlfiddle.com/#!2/9bf21/6(使用mysql-version:5.5.22)

1 个答案:

答案 0 :(得分:4)

这是由bug 70767 on LOCATE() and INSTR()引起的,已经过验证。

尽管INSTR()文档指出它可用于多字节字符串,但正如您所注意到的那样,它似乎不适用于utf8_general_ci这样的排序规则should be case and accent insensitive

  

此函数是多字节安全的,仅当至少一个参数是二进制字符串时才区分大小写。

错误报告指出虽然MySQL正确执行此操作,但只有当 bytes 的数量也相同时才会这样做:

  

但是,您可以轻松地观察到,当在另一个字符串中查找一个字符串时,他们不会(完全)尊重字典。似乎正在发生的事情是MySQL查找一个子字符串,该字符串是与目标完全相同的目标,其字节长度与目标完全相同。这很少是真的。

要隐藏报告示例,请创建下表:

create table t ( needle varchar(10), haystack varchar(10)
                  ) COLLATE=utf8_general_ci;
insert into t values ("A", "a"), ("A", "XaX");
insert into t values ("A", "á"), ("A", "XáX");
insert into t values ("Á", "a"), ("Á", "XaX");
insert into t values ("Å", "á"), ("Å", "XáX");

然后运行此查询,您可以看到演示的相同行为:

select needle
     , haystack
     , needle=haystack as `=`
     , haystack LIKE CONCAT('%',needle,'%') as `like`
     , instr(needle, haystack) as `instr`
  from t;

SQL Fiddle