SQL, как сделать LIKE поиск по каждому значению объявленной переменной - PullRequest
1 голос
/ 06 ноября 2019

У меня есть запрос, в котором я пытаюсь выполнить поиск LIKE по каждому значению объявленной переменной, вместо того, чтобы выполнять поиск по всему значению поля / строке.

Пример:

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

Я ищу запись "Джон и Джейн Смит". Запрос выше не возвращает результат. Если пользователь ищет только «Джон» ИЛИ «Смит», возвращается слишком много результатов.

Я пытаюсь получить запрос для поиска, как запрос ниже:

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

Я искал много вариантов, но не уверен, что мои условия поиска не верны, я ещенайти решение.

Ответы [ 3 ]

1 голос
/ 06 ноября 2019

Полнотекстовый поиск кажется лучшим подходом. Но вы можете аппроксимировать это на уровне слов, разделив поисковый запрос и ища каждое отдельное слово:

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);

При этом используется функция string_split(), доступная в более поздних версиях SQL Server. Существуют онлайн-версии функции для более старых версий.

1 голос
/ 06 ноября 2019

Ответ был получен / принят, прежде чем я смог опубликовать, и то, что написал @ 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 исключит «Мистер Смитерс».

1 голос
/ 06 ноября 2019

Я бы попробовал заменить пробелы в @name на '% %' Что-то вроде

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