【问题标题】:SQL how to do a LIKE search on each value of a declared variableSQL如何对声明变量的每个值进行LIKE搜索
【发布时间】:2019-11-06 17:46:12
【问题描述】:

我有一个查询,我试图对声明变量的每个值进行 LIKE 搜索,而不是对整个字段值/字符串进行类似搜索。

示例:

    DECLARE @name VARCHAR(30)
    SET @name = 'John Smith'
    SELECT name FROM customers WHERE name like '%'+ @name + '%'

我要找的唱片是“John and Jane Smith”。上面的查询返回 NO 结果。如果用户仅搜索“John”或仅搜索“Smith”,则返回的结果太多。

我正在尝试让查询像下面的查询一样进行搜索:

    SELECT name from customers WHERE name LIKE '%John%  %Smith%'

我已经搜索了很多选项,但不确定我的搜索词是否不正确,我还没有找到解决方案。

【问题讨论】:

  • 您最好使用 FTS,而不是创建带有 LIKE 子句的查询,其中前导和尾随字符是通配符。也就是说,除非术语的顺序很重要,否则您想要的结果将是 SELECT name from customers WHERE name LIKE '%John%' AND name LIKE '%Smith%'
  • 我的第一个选择是使用 CONTAINS 但在此表上没有全文索引。我也想不到。
  • 伊戈尔,我也可以用这个对吗? SELECT name from customers WHERE name LIKE '%John% %Smith%' 以获得相同的结果?
  • 否,结果可能因输入而异。如果名称被输入/存储为姓氏,则您的查询不会拉回任何名字,但我的名字会。此外,您的查询要求字段中的 2 个名称之间有一个空格。
  • 是的,但这并不意味着它应该;来自为这样的公司工作的人,他们设计了这样的系统,并迅速向他们展示了为什么这是一个坏主意。因为他们问的正是你的问题类型,而且'John Smith' != 'John and Jane Smith'

标签: sql sql-server variables sql-like declare


【解决方案1】:

我会尝试用'% %' 替换您的@name 中的空格 类似的东西

SET @nameFilter = REPLACE(@name,' ','% %')
SELECT name FROM customers WHERE name like '%'+ @ nameFilter + '%'

【讨论】:

  • 我确实尝试在空格上使用 REPLACE() 但它有点难看,不知道如何完成它。可以举个例子吗?
  • @Larnu 你有上面提到的 REPLACE 的例子吗?我想试试这个选项
  • @sugar2code 这工作谢谢!我将替换移到了 where 子句中,其中声明了 name 变量并且效果很好。
【解决方案2】:

全文搜索似乎是最好的方法。但是您可以通过拆分搜索词并查找每个单独的词来在词级别进行近似:

with words as (
      select value as word
      from string_split(@name)
     )
select c.name
from customers c cross apply
     (select count(*) as cnt
      from words w
      where c.name like '%' + c.word + '%'
     ) w
where w.cnt = (select count(*) from words);

这使用了 SQL Server 较新版本中提供的string_split() 功能。旧版本的功能有在线版本。

【讨论】:

  • 谢谢 Gordon,我将使用这个查询来学习新的东西。我以前没有使用过 string_split,谢谢。
【解决方案3】:

在我发布之前已回答/接受,@sugar2Code 发布的内容是我将如何做的。

也就是说,我不清楚您是否希望第一个 姓需要相似,或者只是其中一个。我放在一起的内容将允许您决定使用参数。

-- Sample Data
DECLARE @t TABLE (CustomerName VARCHAR(30))
INSERT  @t VALUES('Johny Smith'),('Freddie Roach'),('Mr. Smithers'),('Johnathan Smithe');

-- User Arguments
DECLARE 
  @name         VARCHAR(30) = 'John Smith',
  @partialmatch BIT         = 1;

-- Dynamic Solution
SELECT 
  t.CustomerName,
  FNMatch = SIGN(pos.F),
  LNMatch = SIGN(pos.L)
FROM   @t AS t
CROSS JOIN 
(
  SELECT SUBSTRING(@name,1,f.Mid-1), SUBSTRING(@name,f.Mid+1,8000)
  FROM   (VALUES(CHARINDEX(' ',@name))) AS f(Mid)
) AS f(FName,LName)
CROSS APPLY (VALUES (CHARINDEX(f.FName,t.CustomerName), CHARINDEX(f.LName,t.CustomerName))) AS pos(F,L)
WHERE (@partialmatch = 0 AND pos.F*pos.L > 0)
   OR (@partialmatch = 1 AND pos.F+pos.L > 0);

当@partialmatch = 1 你得到:

CustomerName                   FNMatch     LNMatch
------------------------------ ----------- -----------
Johny Smith                    1           1
Mr. Smithers                   0           1
Johnathan Smithe               1           1

将@partialMatch 设置为 0 将排除“Mr. Smithers”。

【讨论】:

  • 哇哦!这更有帮助,非常感谢您。我通过这个解决方案学到了很多新东西,并且有多种选择。对此,我真的非常感激!谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-10
  • 1970-01-01
  • 2016-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多