我需要编写一个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
会更好吗?我想知道最好的方法是什么?
答案 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;