选择查询以匹配具有多个关键字的多个列

时间:2017-03-09 15:16:53

标签: sql sql-server tsql

我需要编写一个select查询,它将在单个表中搜索从用户输入查询字符串中获取的单词,如"John Doe Engineering"。该字符串可以包含单个或多个单词。查询字符串将作为参数传递给存储过程。总共有大约20个需要搜索的列。我的第一个想法是这样的:

SELECT *
FROM Employees
WHERE FirstName LIKE '%John%' OR FirstName LIKE '%Doe%' OR FirstName LIKE '%Engineering%'
WHERE LastName LIKE '%John%' OR LastName LIKE '%Doe2%' OR LastName LIKE '%Engineering%'
WHERE Manager LIKE '%John%' OR Manager LIKE '%Doe%'OR Manager LIKE '%Engineering%'
WHERE Department LIKE '%John%' OR Department LIKE '%Doe%'OR Department LIKE '%Engineering%'
--repeat for 16 more table columns

但我不确定如何根据用户查询字符串输入最好地生成查询语法。此外,这似乎是一个非常低效的查询。在这种情况下使用full text search会更好吗?我想知道最好的方法是什么?

1 个答案:

答案 0 :(得分:-1)

正如其他人所说的那样 - 全文搜索可能是此类事情的最佳解决方案。也就是说,我认为提供T-SQL解决方案会很有趣。

快速免责声明1

*我强烈建议您不要使用下面的解决方案 - 这是一个有趣的小SQL练习;表现会很糟糕。另外 - 我演示了两种非常有效的方法来分割字符串:一种是使用Jeff Moden的DelimitedSplit8K,另一种是使用PARSENAME *

快速免责声明2

我应该指出将列连接成一个字符串的问题,正如一对人建议的那样 - 它可能导致误报;请考虑以下查询:

DECLARE @search varchar(100) = 'ab';

WITH sampleData AS (SELECT fn, ln FROM (VALUES ('aa', 'bb'), ('cc', 'dd')) t(fn,ln))
SELECT * 
FROM sampleData
WHERE CONCAT(fn,ln) LIKE '%'+@search+'%';

上面的查询将返回第一条记录,即使" ab"在任一列中都不存在。因此,您可以将WHERE(或John的示例中的CHARINDEX)更改为:

WHERE CONCAT(fn, '|||', ln) LIKE '%'+@search+'%';

我的解决方案

-- SAMPLE DATA 
-------------------------------------------------
DECLARE @employees TABLE 
(
  FirstName  varchar(100),
  LastName   varchar(100),
  Manager    varchar(100),
  Department varchar(100)
);

INSERT @employees
SELECT * 
FROM 
(
  VALUES 
    ('bob', '****', 'ddd', 'sss'),
    ('fff', 'fred', 'obx', 'ccc'),
    ('Sue', 'abcd', 'ddd', 'zzz'),
    ('ddd', 'dcba', '123', 'fobbb')
) xx(x1, x2, x3, x4);

-- Solution #1: when @search has <= 4 "items"
-------------------------------------------------
DECLARE @search varchar(100) = 'xx bb ff zz';

SELECT e.*
  --,PARSENAME(REPLACE(@search,' ','.'), N) AS matchedPattern
FROM (VALUES (1),(2),(3),(4)) t(n)
CROSS JOIN @employees e
WHERE 
  CHARINDEX
  (
    PARSENAME(REPLACE(@search,' ','.'), N), 
    CONCAT(FirstName, '|||', LastName, '|||', Manager, '|||', Department)
  ) > 0;

-- Solution #2: when @search has (or can have) > 4 "items"
-------------------------------------------------

-- for this you will need delimitedsplit8k: http://www.sqlservercentral.com/articles/Tally+Table/72993/
SELECT e.*
FROM dbo.delimitedsplit8k(@search, ' ')
CROSS JOIN @employees e
WHERE 
  CHARINDEX
  (
    item, 
    CONCAT(FirstName, '|||', LastName, '|||', Manager, '|||', Department)
  ) > 0;