3

我有一个包含 5 个字段的数据库,它们是:姓名、地址、身份证、城镇、街道

然后我有一个接受一个参数的 PHP 查询。在此参数中,您可以输入您喜欢的任何字段,并且结果必须仍然准确。

例如,如果我在搜索框中输入 john doe 滑板街,您将获得所有名称为 John Doe 且居住在名为 Skate Street 的街道的记录。

另外,请注意姓名以姓氏的顺序存储在一个字段中(我无法更改,因为这是必须的,所以请不要告诉我最好更改它...我知道:))。显然,我希望可以按任何顺序输入姓名,无论是 NAME SURNAME 还是 SURNAME NAME。

我的想法是首先附加前两个输入的参数作为名称。我会告诉我的客户,前两个参数必须是姓名和姓氏或姓氏和姓名。在名称之后,他可以按照他喜欢的任何顺序输入任何订单属性,即

这些将被接受:

name surname idcard town street
surname name idcard town street
name surname town idcard street
surname name address street idcard

这些将不被接受:

idcard town name surname street
town name surname idcard

原因很简单,我们会使查询过于复杂(因为姓名/姓氏原因,并且它们在同一个字段中)

如果有一种方法可以在没有很多复杂情况的情况下实现后者,我也想听听。

我希望能在这件事上得到一些帮助

提前谢谢了

4

3 回答 3

4

对于诸如 MySQL 之类的 RDBMS,您似乎所追求的那种搜索并不是真正的最佳选择。并且指定允许的搜索格式通常不利于可用性,除非它是一个相当特定的域。

保持它非常通用,在三个字段中搜索“Persons Name Fake Street”的查询可能是这样的:

SELECT * FROM Users
WHERE (FirstName LIKE "%Persons%"
OR LastName LIKE "%Persons%"
OR Address LIKE "%Persons%")
AND (FirstName LIKE "%Name%"
OR LastName LIKE "%Name%"
OR Address LIKE "%Name%")
AND (FirstName LIKE "%Fake%"
OR LastName LIKE "%Fake%"
OR Address LIKE "%Fake%")
AND (FirstName LIKE "%Street%"
OR LastName LIKE "%Street%"
OR Address LIKE "%Street%")

这应该找到任何具有与给定信息相匹配的详细信息的成员。但不是很优雅,只会随着更长的查询和更多的字段而变得更糟。它的效率也非常低,并且随着表的变长会很快陷入困境——它无法使用索引。它也不能帮助您获得顶部的“最佳”匹配(如果有很多结果)

更好的解决方案可能是通过创建一个单独的表来使用 MySQL 全文索引,该表可以使用全文索引进行搜索以查找相关用户。我对这个解决方案了解不多。

另一种选择可能是使用外部索引工具,例如 Lucene。虽然它增加了更多复杂性,但它允许额外的功能,例如字段加权。因此,例如,名称可以被视为比地址更重要。这也可以按相关性顺序排列结果。

正确的解决方案取决于您的要求(一如既往),但这些想法可能值得研究。

于 2010-02-01T12:52:58.993 回答
0

这并不完美,但您的设计也是如此,因此值得:

标记输入参数“name surname idcard town street”,然后连接数据库中的字段并执行一系列类似或的操作:

psudocode
---------
where
name+address+idcard+town+street like %input_token1% or
name+address+idcard+town+street like %input_token2% or
...
name+address+idcard+town+street like %input_token5%
于 2010-02-01T12:57:06.493 回答
0

我会尝试使用正则表达式拆分单词并将它们放入一个临时表中,您可以使用它加入您的 Person 表。

正则表达式可能看起来像这样

preg_match_all('/(\S+)*\s+/im', $input, $value, PREG_PATTERN_ORDER);
for ($i = 0; $i < count($value[0]); $i++) {
    # Matched text = $result[0][$i];
}

在 SQL Server 中查找结果的脚本可能如下所示。我没有足够的 MySQL 知识来提出 MySQL 的替代方案,但您应该明白这一点

这个想法的要点是在您希望搜索的每一列上加入输入表。该where子句处理输入值至少在有输入值的列数中找到的事实。

DECLARE @Table TABLE (Name VARCHAR(20), Surname VARCHAR(20), Address VARCHAR(20), IDCard VARCHAR(20), Town VARCHAR(20), Street VARCHAR(20))
DECLARE @Inputs TABLE (Value VARCHAR(32))

INSERT INTO @Table VALUES ('Doe', 'John', 'Dontknow', 'Dontknow', 'US', 'Skate')
INSERT INTO @Inputs VALUES ('%John%')
INSERT INTO @Inputs VALUES ('%Doe%')
INSERT INTO @Inputs VALUES ('%Skate%')

SELECT  t.*
FROM    @Table t
        LEFT OUTER JOIN @Inputs i_name ON t.Name LIKE i_name.Value     
        LEFT OUTER JOIN @Inputs i_surname ON t.SurName LIKE i_surname.Value        
        LEFT OUTER JOIN @Inputs i_address ON t.Address LIKE i_address.Value
        LEFT OUTER JOIN @Inputs i_idcard ON t.IDCard LIKE i_idcard.Value
        LEFT OUTER JOIN @Inputs i_town ON t.Town LIKE i_town.Value
        LEFT OUTER JOIN @Inputs i_street ON t.Street LIKE i_street.Value
        CROSS APPLY (SELECT inputCount = COUNT(*) FROM @Inputs) cnt
WHERE   cnt.inputCount <= 
          CASE WHEN i_name.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_surname.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_address.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_idcard.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_town.Value IS NULL THEN 0 ELSE 1 END
          + CASE WHEN i_street.Value IS NULL THEN 0 ELSE 1 END
于 2010-02-01T13:37:07.127 回答