【问题标题】:Performing a search on first and last name columns with a single search string that has more than 2 words使用包含 2 个以上单词的单个搜索字符串对名字和姓氏列执行搜索
【发布时间】:2016-10-21 17:29:03
【问题描述】:

我有一个查询,该查询当前采用单个用户提供的搜索字符串,并尝试搜索一个表,该表包含一个单独的 firstName 和 lastName 列。如果搜索字符串中有空格,那么它运行的查询本质上是这样的:

SELECT * FROM table
WHERE table.firstName LIKE @firstName + '%'
AND table.lastName LIKE @lastName + '%'

我们不需要关心搜索字符串中没有空格的情况。

一般情况很简单 - 将搜索字符串用空格分隔,第一部分是名字,第二部分是姓氏。所以,“鲍勃·史密斯”变成了

@firstName = "Bob", @lastName = "Smith"

我关心的是如何处理名称超过两个单词的情况。像

这样的情况
table.firstName        table.lastName
---------------        --------------
Bob                    van Smith
Billy Bob              Smith
Bob                    van der Smith  
Billy Bob              van der Smith

等等。现在我们在第一个空格上进行拆分,所以第一个示例“Bob van Smith”将起作用,因为它会分解为

@firstName: "Bob", @lastName: "van Smith" 

但是,这并没有捕捉到第二种情况“Billy Bob Smith”,因为它分裂成

@firstName: "Billy", @lastName: "Bob Smith"

当前设置也适用于第三个测试用例,因为它分为

@firstName: "Bob", @lastName: "van der Smith"

如果有办法让它发挥作用,最后一种情况将是加分。

我的第一个想法是将查询修改为

SELECT * FROM table
WHERE table.firstName + ' ' +  table.lastName LIKE '%' + @searchString + '%'

但这被否决了,因为我们不希望有人只搜索字母“a”,例如返回大量记录,而双通配符会创建这些记录。

进行这种字符串拆分/搜索有什么技巧吗?这不可能是第一次出现问题,但是在互联网上搜索除了“空间分割,但请注意,如果名称中有 3 个或更多单词,它将不起作用。”

我觉得类似于将“名称之间”作为@firstName 和@lastName 的一部分并做一些聪明的事情,或者使SQL 部分更通用,然后在我的C# 代码中使用LINQ 进行额外的过滤,但我想找到一个解决方案。

【问题讨论】:

  • 这是一个重要的问题。例如,像 Maria de los Angeles Gomez de la Cruz 这样的名字。我认为你的设计把你放在了一个无法轻易逃脱的盒子里。一个强大的名称匹配算法必须考虑到人们以不同方式对待相同名称的可能性,并允许名称单词丢失、跨越第一个/最后一个边界、拼写错误等。这对于一个简单的 SO 答案来说太宽泛了。
  • @hatchet 是的,这就是我害怕的。我继承了这个设计,并且拒绝对其进行根本性的改变,所以我认为看看是否有我遗漏的技巧不会有什么坏处

标签: c# tsql


【解决方案1】:

我是这样做的:

  1. 使用通配符将每个空格分隔的名称添加到两列(我无法控制名称顺序或要求名字和姓氏)。
  2. 然后我根据每个匹配项分配一个分数(即,它是否是一个完整的单词匹配,并且在名字和姓氏列中是否都匹配)
  3. 我还有最少要搜索的字母数(最少 2 个字母)

这对我来说效果很好。您仍然可以为小词生成大量匹配项。匹配的排名会将较差的部分匹配推到列表底部。

【讨论】:

  • 我喜欢这个想法,我认为它可能对将来可能会发现这个问题的其他人有所帮助。不幸的是,就我而言,要求是“匹配”或“不匹配”。我怀疑我有太多限制,无法真正做到这一点,看起来我是对的
  • 你在哪里说匹配或不匹配 - 你是指全名吗?如果是这样,只需 concat 你的 Firstname/Lastname 列首先搜索(即 Bob Smith 不匹配 Bob van Smith,你是金子)。如果您的意思是不匹配部分单词匹配但不匹配所有名称的灵活性,您也可以通过拆分搜索词和 FirstName / LastName 列中的词并按顺序评估它们来做到这一点。
  • 我们最终提出了一个非常复杂的想法,即在存在单个空格时维护名字和姓氏搜索,但如果有多个空格,则像您在此处建议的那样连接并进行直接比较。虽然我们的情况非常独特,但我认为您的回答更适合一般用途,所以我将其标记为已接受
【解决方案2】:

如果您使用的是 sql server 2012+,您可以使用CONCAT (Transact-SQL)

select *  from [table] where CONCAT(FirstName, ' ', LastName) like '%Bob Smith%'

在这种情况下,您不需要拆分任何内容,只需 CONCAT 您的 FirstName 和 LastName 并将其与您的输入进行比较。如果您总是要从输入中接收全名,您甚至可以去:

select *  from [table] where CONCAT(FirstName, ' ', LastName) ='Bob Smith'

当然你会用sql参数我写成纯文本只是为了清楚使用全名输入。

【讨论】:

  • 这会导致对每个查询进行表扫描吗?
  • @hatchet 可能我不知道他是如何设置他的桌子的,有用于此类检查的分析器。
  • 这基本上不是我的想法被击落了吗?
  • @Adam 我不明白你的意思。当然,这会比在 2 列中使用 like 搜索更快。
【解决方案3】:

如果您只是在寻找与用户输入的内容完全匹配的内容,请尝试以下操作:

select * 
from table
where @searchString like table.firstName + '%' and @searchString like '%' + table.lastName
and len(table.firstName + ' ' + table.lastName) = len(@searchString)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 2012-02-19
    • 2022-01-03
    相关资源
    最近更新 更多