MySQL搜索查询在两个不同的字段上

use*_*677 5 mysql

我需要使用LIKE函数搜索两个字段,并且也应该以相反的顺序匹配.我的表使用没有全文搜索的InnoDB.

考虑以下情况:

我有一个带有first_name和last_name列的用户表.在它上面,有一行具有以下值:

{
    first_name: 'Ludwig',
    last_name: 'van Beethoven',
}
Run Code Online (Sandbox Code Playgroud)

案例:

  1. 可以搜索"Ludwig van Beethoven"
  2. 可以搜索"Beethoven Ludwig"
  3. 可以搜索"路德维希"
  4. 可以搜索"贝多芬"

我试过这个SQL语句,但没有运气.

SELECT CONCAT(first_name, ' ', last_name) as fullname 
  FROM users 
 WHERE fullname LIKE '%Ludwig van Beethoven%';
Run Code Online (Sandbox Code Playgroud)

Wil*_*urn 7

您需要在where子句中重新声明concat表达式.

 SELECT CONCAT(first_name, ' ', last_name) as fullname 
      FROM users 
     WHERE CONCAT(first_name, ' ', last_name) LIKE '%doe%';
Run Code Online (Sandbox Code Playgroud)

不幸的是"as"只是创建一个列别名,而不是你可以在其他地方使用的变量.

  • @Andy:绝对同意你应该避免使用`WHERE`子句中的函数*,你有其他选项*,但它们不会*自动*坏,如果函数可以在索引上计算(请参阅我对我的回答)意思是).我不认为`HAVING`在这里有帮助(我比较了执行计划;请参阅我的答案中的注释),但是对于你为什么会这样做的任何参考都会非常感兴趣. (2认同)

T.J*_*der 6

主要的事情

请确保你有一个复合索引first_namelast_name.否则,无论您如何处理此问题,最终都可以轻松完成全表扫描.因此,如果您还没有,请创建一个:

CREATE INDEX users_firstandlast ON users(first_name, last_name);
Run Code Online (Sandbox Code Playgroud)

语法选项

一旦该指数到位,您就有了一些选择:

选项1:正如Willis Blackburn所说,重复CONCAT你的WHERE子句(因为AS没有创建你可以在WHERE子句中使用的名称):

SELECT CONCAT(first_name, ' ', last_name) as fullname 
FROM users 
WHERE CONCAT(first_name, ' ', last_name) LIKE '%doe%';
Run Code Online (Sandbox Code Playgroud)

使用EXPLAIN您的具体情况进行检查,但在我的测试中,它说,它采用了复合索引,即使您正在使用的函数中的WHERE条款.

选项2:在这种特殊情况下,你总是可以LIKE在你的WHERE子句中使用两个:

SELECT CONCAT(first_name, ' ', last_name) as fullname 
FROM users 
WHERE first_name LIKE '%doe%' or last_name LIKE '%doe%';
Run Code Online (Sandbox Code Playgroud)

再次,这可以使用复合索引(而不会使用first_namelast_name列上的单个索引- 如果你没有使用通配符,但是根据EXPLAIN[并且你的里程可能会有所不同,请务必检查) ],在这种情况下,它与表扫描一起).

选项3他的回答中,安迪说你可以用HAVING它.我阅读MySQL手册表明它将首先构建结果集,然后HAVING才将其发送到客户端之前应用到最后,因此我对此持怀疑态度.但是,在我的快速和肮脏的测试中,EXPLAIN告诉我如果你有上面提到的复合索引,那么HAVING版本会进行索引搜索,而不是表扫描.如果您使用真实数据进行测试,那么这对您来说可能是一个不错的选择.这种方式的使用HAVING是MySQL扩展(不是标准的),但是再次,CONCAT所以我们已经进入MySQL特定的东西了.:-)但是,再次,仔细检查你的现实生活环境.

结论

如果您还没有索引,那么创建索引,如果远程可能,我会使用选项2; 否则,选项1除非你能找到(或者Andy可以提供)HAVING没有建立大量中间结果集的东西的参考(如果非标准的话,它会非常酷,如果没有的话).无论如何,请EXPLAIN在您的特定环境中进行检查和测试.