2017-05-08 68 views
5

的所有組合在我的數據庫有一個表稱爲author,這4列:搜索第一,中間名和姓

  • AUTHORID
  • 的firstName
  • 中間名
  • lastName的

例如,用戶正在搜索Edgar Allan Poe。在我們的桌子Edgar Allan Poe保存爲:名字 - Edgar,middleName - Allan和姓氏 - Poe。這個查詢非常簡單。但是,如何編寫一個不僅與Edgar Allan Poe,還包括Poe Allan Edgar,Edgar Poe,Allan Poe,Edgar Allan,Allan Edgar Poe相匹配的查詢,而無需對我們自己寫出所有這些可能的組合?此外,當用戶正在搜索時,他/她正在搜索「Edgar Allan Poe」或「Poe Allan Edgar」,而不是在單獨的字段中搜索。

+0

編輯你的問題,標籤與你所使用的數據庫的數據庫。 –

+0

_all_組合是否可以接受? – Manngo

+0

@Manngo是的,所有的組合都可以接受。 – Xty83a

回答

2

請嘗試以下...

DROP PROCEDURE IF EXISTS SimilarNames; 
DELIMITER // 
    CREATE PROCEDURE SimilarNames(authorFullName VARCHAR(250)) 
    BEGIN 
     SET @authorFullNameCommad = CONCAT('\'', 
              REPLACE(authorFullName, 
                ' ', 
                '\', \''), 
              '\''); 

     SET @selectStatementString := CONCAT("SELECT authorID,", 
               "  firstName,", 
               "  middleName,", 
               "  lastName ", 
               "FROM author ", 
               "WHERE ((firstName IN (", 
               @authorFullNameCommad, 
               ")) + (middleName IN (", 
               @authorFullNameCommad, 
               ")) + (lastName IN (", 
               @authorFullNameCommad, 
               "))) >=2;"); 

     PREPARE selectStatement FROM @selectStatementString; 
     EXECUTE selectStatement; 
     DEALLOCATE PREPARE selectStatement; 
    END // 
DELIMITER ; 
CALL SimilarNames('Edgar Allan Poe'); 

該解決方案通過創建一個名爲PROCEDURESimilarNames(後DROP平的任何現有的PROCEDURE的版本)開始。此PROCEDURE將傳遞給它的名稱(例如'Edgar Allan Poe')存儲在參數變量authorFullName中。

一旦開始,PROCEDURE首先將字符串(如Edgar Allan Poe)轉換爲'Edgar', 'Allan', 'Poe'並將其存儲在變量@authorFullNameCommad中。

然後使用CONCAT()函數來形成將生成我們的結果的SQL語句的文本。其中authorFullNameEdgar Allan Poe下面的語句生成並存儲在@selectStatementString ...

SELECT authorID, 
     firstName, 
     middleName, 
     lastName 
FROM author 
WHERE ((firstName IN ('Edgar', 'Allan', 'Poe')) + (middleName IN ('Edgar', 'Allan', 'Poe')) + (lastName IN ('Edgar', 'Allan', 'Poe'))) >=2; 

的SQL語句然後PREPARE d和EXECUTE d,從而產生當PROCEDURE被稱爲所需的列表,這可以用做...

CALL SimilarNames('Edgar Allan Poe'); 

請注意,你不這樣做必須在第一次申報後申報PROCEDURE。即下面的工作就好了... ...

CALL SimilarNames('Edgar Allan Poe'); 
CALL SimilarNames('James Tiberius Kirk'); 

而且,請注意,這個特殊的方法容易SQL注入。如果你願意的話,我可以開發一個防止這種情況的版本 - 現在只是晚了,我很快就會睡覺。

我的發言是針對使用下面的腳本創建了一個樣本數據集測試...

CREATE TABLE author 
(
    authorID  INT NOT NULL AUTO_INCREMENT, 
    firstName VARCHAR(50), 
    middleName VARCHAR(50), 
    lastName  VARCHAR(50), 
    PRIMARY KEY (authorID) 
); 
INSERT INTO author (firstName, 
        middleName, 
        lastName) 
VALUES ('Edgar', 'Allan', 'Poe'), 
     ('Poe', 'Allan', 'Edgar'), 
     ('Edgar', 'Poe', ''), 
     ('Edgar', '', 'Poe'), 
     ('', 'Edgar', 'Poe'), 
     ('Allan', 'Poe', ''), 
     ('Edgar', 'Allan', ''), 
     ('Allan', 'Edgar', 'Poe'), 
     ('Edgar', 'Allan', 'Allan'), 
     ('James', 'Tiberius', 'Kirk'), 
     ('Karl', 'Ignatius', 'von Bach'), 
     ('Edgar', 'Poe', 'xyz'), 
     ('Allanah', 'Poelsen', ''); 

的結果如我所料。

如果您有任何問題或意見,請隨時發佈相應評論。

進一步閱讀

https://dev.mysql.com/doc/refman/5.7/en/call.html(對MySQL的CALL語句)

https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_concat(對MySQL的CONCAT()功能)

https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html(對MySQL的CREATE PROCEDURE語句)

https://dev.mysql.com/doc/refman/5.7/en/deallocate-prepare.html(對MySQL的DEALLOCATE STA tement)

https://dev.mysql.com/doc/refman/5.7/en/stored-programs-defining.html(對MySQL的DELIMITER命令)

https://dev.mysql.com/doc/refman/5.7/en/drop-procedure.html(對MySQL的DROP PROCEDURE語句)

https://dev.mysql.com/doc/refman/5.7/en/execute.html(對MySQL的EXECUTE語句)

https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in(對MySQL的IN運營商)

https://dev.mysql.com/doc/refman/5.7/en/prepare.html(在MySQL的PREPARE sta tement)

https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_replace(對MySQL的REPLACE()功能)

https://dev.mysql.com/doc/refman/5.7/en/set-statement.html(對MySQL的SET語句)

+0

非常感謝。絕對美妙的解決方案和非常明確的解釋。但是當我把代碼放在mysql中時,它說:意外的字符(near;)。 – Xty83a

+0

請重現錯誤信息的全文 - 我對其他線索特別感興趣,例如行號。 – toonice

+0

數字的行數是9,22,24,25,26。我使用phpmyadmin,並且在代碼行中有一個紅色的小圖標,它只會顯示:'意外的字符。 (near;) – Xty83a

3

在任何數據庫,你可以做這樣的事情:

where firstName in ('Edgar', 'Allan', 'Poe') and 
     middleName in ('Edgar', 'Allan', 'Poe') and 
     middleName <> firstName and 
     lastname in ('Edgar', 'Allan', 'Poe') and 
     lastname not in (firstname, middleName) 

這其實是很容易擴展到更多的名字,如果你喜歡 - 假設名稱是不同的,如你的例子(如果你想要允許具有重複名稱的作者,只需從上面的查詢中刪除第3行和第5行)。

但是,根據您的數據庫,您可能希望使用正則表達式或全文搜索。

+1

https://en.wikipedia.org/wiki/Helle_Helle,https://en.wikipedia.org/wiki/Holling_C._Holling :-) – paxdiablo

+0

@paxdiablo。 。 。你的榜樣比Sirhan Sirhan更好。 –

0

對於通用DBMS,假設您的意圖只是爲了簡化您的查詢,一種方法是將單獨的計算列添加到作者表中,其中一個在插入和更新時觸發。

換句話說,有一個叫clumn和searchFullName已經將其設置爲:

<space><firstName><space><secondName><space><lastName><space> 

然後你的查詢變得(相對)簡單:

select something from author 
where searchFullName like '% Poe %' 
    and searchFullName like '% Edgar %' 

這不會是快如閃電對於大型表格,但它應該達到你想要的。