我需要使用LIKE函数搜索两个字段,并且也应该以相反的顺序匹配。我的表使用的InnoDB没有全文搜索。
考虑以下情况:
我有一个带有first_name和last_name列的用户表。在它上面,有一行具有以下值:
{
first_name: 'Ludwig',
last_name: 'van Beethoven',
}
例:
我尝试了这个SQL语句,但没有运气。
SELECT CONCAT(first_name, ' ', last_name) as fullname
FROM users
WHERE fullname LIKE '%Ludwig van Beethoven%';
答案 0 :(得分:7)
您需要在where子句中重新声明concat表达式。
SELECT CONCAT(first_name, ' ', last_name) as fullname
FROM users
WHERE CONCAT(first_name, ' ', last_name) LIKE '%doe%';
不幸的是“as”只是创建一个列别名,而不是你可以在其他地方使用的变量。
答案 1 :(得分:6)
确保您在first_name
和last_name
上有一个复合索引。否则,无论您如何处理此问题,它都非常容易最终进行全表扫描。因此,如果您还没有,请创建一个:
CREATE INDEX users_firstandlast ON users(first_name, last_name);
一旦该指数到位,您就有了一些选择:
选项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%';
使用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%';
同样,这可以使用复合索引(而不会使用first_name
和last_name
列上的单个索引 - 如果您没有使用通配符,但根据EXPLAIN
[并且您的里程可能会有所不同,请务必检查],在这种情况下,它会与表格扫描一致。)
选项3 在his answer中,Andy表示您可以使用HAVING
。我的read of the MySQL manual建议它首先构建结果集,然后在发送给客户端之前在最后应用HAVING
,所以我对此持怀疑态度。 但是,在我的快速和肮脏的测试中,EXPLAIN
告诉我,如果你有上面提到的复合索引,HAVING
版本会进行索引搜索,而不是表扫描。如果您使用真实数据进行测试,那么这对您来说可能是一个不错的选择。以这种方式使用HAVING
是MySQL扩展(不是标准的),但是再次,CONCAT
也是如此,所以我们已经进入了MySQL特定的东西。 :-)但是,再次,仔细检查你的现实生活环境。
如果您还没有索引,请创建索引,如果远程可能,我会使用选项2;否则,选项1除非您能找到(或者Andy可以提供)HAVING
没有建立大量中间结果集的参考(如果不是非标准的话,它会非常酷,如果没有的话)。无论如何,请在您的特定环境中查看EXPLAIN
并进行测试。
答案 2 :(得分:2)
SELECT * FROM users WHERE CONCAT(first_name,'',last_name)LIKE'%Ludwig%'或CONCAT(last_name,'',first_name)LIKE'%Ludwig%';
所有返回的搜索案例包括“Beethoven Ludwig”。
答案 3 :(得分:-2)
当你CONCAT()两列时,LIKE变得区分大小写。所以这应该找到你的结果,但不是最佳的表现:
SELECT CONCAT(first_name, ' ', last_name) AS fullname FROM users
WHERE LOWER(CONCAT(first_name, ' ', last_name)) LIKE LOWER('%doe%');
这让MySQL在每一行都可以工作。