2017-05-08 66 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 %' 

这不会是快如闪电对于大型表格,但它应该达到你想要的。