我正在尝试使用简单的已提交字段在MySQL中获取记录。更确切地说,用户输入名称(名字或姓氏或全名),服务器应返回匹配的行。
到目前为止我所做的是:
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%'
我知道我可以拆分原始字符串,但这有一些负面影响,因为你必须处理包含空格的名称,例如'De Gaule'和类似的东西。
答案 0 :(得分:9)
将所有条件都放入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
子句可以提前丢弃行,但是因为在之后之后你不能丢弃它们,所以你已经计算了计算列上的条件,并且必须等到{{1} },它没有任何东西可以使用HAVING
。
答案 1 :(得分:5)
做一个子查询:
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%'
答案 2 :(得分:1)
让我们考虑一些可能的输入:
John
Smith
John Smith
您的初始样本查询是:
SELECT * FROM people
WHERE
firstname LIKE '%user_submitted_data%' OR
lastname LIKE '%user_submitted_data%'
现在,当用户输入第一个输入时,此查询将选择名字中包含“John”的所有人;它还将挑选所有姓氏包含“John”的人(例如,数据库中的所有Johnsons)。同样,第二个输入将选择名字中包含'Smith'的所有人;它还将挑选所有姓氏包含'Smith'的人(例如,Smithsons和Smithers)。到现在为止还挺好;由于区分大小写的问题,它不完美(我会从这里忽略区分大小写,但你可能根本不应该忽略它),但它会没问题。
第三个输入只会选择名字中包含“John Smith”的人;它还将挑选那些姓氏包含“John Smith”的人。然而,很可能很少有人符合这些标准 - 那些名叫约翰史密斯的人将只有名字中的约翰和姓氏中的史密斯。这不太可能是你的想法。
目前尚不清楚表中是否有名为“fullname”的列。如果这样做,那么您可以只匹配该列,而不是分别匹配第一个名称和姓氏。如果不这样做,也许你可以制作这样一个列然后针对它运行查询。
SELECT *
FROM (SELECT firstname || ' ' || lastname AS fullname, ... FROM people) AS t
WHERE t.fullname LIKE '%user_submitted_data%'
这种方法运作得相当好。
但是,如果您担心“戴高乐”(或“戴高乐”)或“Michael van den Berg”这样的名字,那么如果有人进入“Charles Gaulle”或“Michael”,那么匹配就会失败伯格,更不用说迈克尔范登堡了。您可能还需要用'%'符号替换用户输入中的任何空格字符。即使这样,你也要面对这样的问题:单词必须完全按照用户给出的顺序出现 - 这可能无关紧要,但你应该有意识地决定它并不重要。例如,如果输入是'Adam John Smith',那么查询将不会捕获'John Adam Smith';如果输入是'Smith,John',那么它就不会接收任何人(最有可能)。
如果你想管理这个,你可能需要标记用户的输入,并搜索单独的单词。要小心有人问一个单词的子字符串(例如,有人问'de'作为名字) - 目前没有任何查询确保用户输入的单词与值中的整个单词匹配(John vs约翰逊),并且使用SQL标准LIKE运算符这样做已经足够不可能了。
答案 3 :(得分: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进行全文索引。
答案 4 :(得分:0)
尽管使用子查询效果很好,但它会产生影响,因为您没有点击任何索引。
如何向表中添加计算列(firstname || ' ' || lastname
)及其索引?肯定会快得多。
如果你不能这样做,我认为像
那样查询WHERE firstname || ' ' || lastname LIKE '%user_submitted_data%'
仍应比两个OR
和一个子查询更快地工作。