2009-08-22 114 views
5

我想使用简单的使用提交的字段在MySQL中获取记录。更确切地说,用户输入名称(名字或姓氏或全名),服务器应返回匹配的行。在MySQL的HAVING和WHERE子句之间使用'OR'?

我在做什么,到目前为止是这样的:

SELECT * FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' 

,从目前来看效果很好,但(显然)将不会在用户提交的全名工作。有没有办法在整个'WHERE类型条件'和'HAVING类型条件'之间添加OR?这样我可以这样做:

SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' OR 
    HAVING fullname LIKE '%user_submitted_data%' 

我知道我可以只分割原始字符串,但有一定的负面影响,因为你必须处理包含空格,如“德高卢”之类的东西的名称。

回答

4

做一个子查询:

SELECT [some fields] 
FROM 
    SELECT firstname, lastname, CONCAT(firstname, ' ', lastname) as fullname 
    FROM people) AS tmp 
WHERE firstname LIKE '%user_submitted_data%' 
OR lastname LIKE '%user_submitted_data%' 
OR fullname LIKE '%user_submitted_data%' 
+0

谢谢,它修复了它。 – Jimmy 2009-08-22 18:31:14

1

让我们考虑一些可能的输入:

John 
Smith 
John Smith 

您最初的样本查询:

SELECT * FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' 

现在,当用户进入第一输入,这个查询将选择名字中包含'John'的所有人;它也会挑选姓氏中包含“John”的所有人(例如,数据库中的所有Johnsons)。同样,第二个输入将选择名字中包含'Smith'的所有人;它也会挑选姓氏中包含“史密斯”的所有人(例如Smithsons和Smithers)。到现在为止还挺好;它由于区分大小写的问题并不完美(我会忽略区分大小写,但是您可能根本不应该忽略它),但它会一切正常。

第三个输入只会选择名字中包含'John Smith'的人;它也会挑选姓氏中包含“约翰史密斯”的人。然而,很少有人符合这些标准 - 那些叫做约翰史密斯的人将只有约翰的名字,而史密斯只有姓。这不太可能是你想到的。

目前尚不清楚您的表中是否有名为'fullname'的列。如果你这样做,那么你可以匹配该列,而不是单独匹配名字和姓氏。如果你不这样做,也许你可以制造这样一个列,然后运行查询。

SELECT * 
    FROM (SELECT firstname || ' ' || lastname AS fullname, ... FROM people) AS t 
WHERE t.fullname LIKE '%user_submitted_data%' 

这工作相当不错。然而,如果您担心'戴高乐'(或'戴高乐'或'戴高乐'或'迈克尔范登贝格')的名字,那么如果有人进入'戴高乐'或'迈克尔伯格',更别说迈克尔范登堡了。您可能需要用'%'符号替换用户输入中的空格字符。即使那样,你仍然面临这样的问题:单词必须按照用户给定的顺序出现 - 这可能无关紧要,但是你应该有意识地决定它并不重要。例如,如果输入是“亚当约翰史密斯”,那么查询将不会捕获“约翰亚当史密斯”;如果输入是'史密斯,约翰',那么它不会选择任何人(很可能)。

如果你想管理这个,你可能需要标记用户的输入,并搜索单独的单词。小心有人询问某个词的子字符串(例如,有人询问'de'是否是名词) - 目前没有任何查询确保用户输入的单词与值中的整个单词相匹配(John vs约翰逊),并且用SQL标准LIKE算子这样做几乎是不可能的。

+0

感谢您的深入研究。出于某种原因,MySQL似乎对我的系统(OSX)不区分大小写,所以目前它一直工作得很好。就字顺序而言,LIKE运算符非常适合上下文。当用户搜索John Adam Smith时,我不需要(也不想要)Johh Smith出来。搜索样本非常有限。 – Jimmy 2009-08-22 20:01:40

0

您可以参考WHERE子句中计算列,如果你定义一个子查询列:

SELECT p.* 
FROM (
    SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
    FROM people 
) p 
WHERE 
    p.firstname LIKE '%user_submitted_data%' OR 
    p.lastname LIKE '%user_submitted_data%' OR 
    p.fullname LIKE '%user_submitted_data%'; 

但说实话,对于你在做搜索的类型,LIKE使用通配符是一个可怕的解决方案。你应该考虑使用一个FULLTEXT指数:

CREATE FULLTEXT INDEX people_names ON people(firstname, lastname); 

SELECT * 
FROM people 
WHERE MATCH(firstname, lastname) AGAINST(?); 

PS:FULLTEXT指标只能用MyISAM存储引擎的工作。另一个解决方案,更快速,是使用Sphinx Search进行全文索引。

0

虽然使用子查询效果很好,但它会产生影响,因为您没有触及任何索引。

如何在表中添加一个计算列(firstname || ' ' || lastname)和它的索引?肯定会更快。

如果你不能这样做,我认为像查询

WHERE firstname || ' ' || lastname LIKE '%user_submitted_data%' 

应该仍然工作快超过两个OR S和一个子查询。

+0

我不认为有办法在MySQL中做索引计算列,或者显示我的研究。如果这是可行的,我很乐意听到它。 – Jimmy 2009-08-22 20:16:22

+0

你可能是对的,我想根本没有办法使用计算列! – Sklivvz 2009-08-22 20:58:37

+0

同时MySQL支持索引计算列。但是如果模式以占位符('''')开头,则LIKE条件不能使用索引。 – 2016-09-08 23:01:36

7

只需将所有条件放入HAVING条款。

SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
FROM people 
HAVING firstname LIKE '%user_submitted_data%' 
OR  lastname LIKE '%user_submitted_data%' 
OR  fullname LIKE '%user_submitted_data%

WHERE条款可能早放弃行,但因为你不能抛弃他们,直到后您已经评价计算列的条件,那要等到HAVING,能带给你什么用WHERE

+0

为我工作,看起来像比使用子查询更优雅的解决方案。谢谢! – 2016-12-23 19:27:36