2009-08-22 106 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