2017-03-09 88 views
0

我需要編寫一個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

SQL Server有一個叫做全文搜索功能。可能你想在這裏。 – Hogan

+1

我在想「全文搜索」。 –

+1

@GordonLinoff - 有3秒鐘! :D – Hogan

回答

-1

正如其他人所說 - 全文搜索可能是這類事情的最佳解決方案。也就是說,我認爲提供T-SQL解決方案會很有趣。

快速免責聲明1

*我強烈建議您不要使用以下解決方案 - 這是旨在成爲一個有趣的小SQL鍛鍊;表現會很糟糕。而且 - 我演示了兩個非常有效的方式來分割字符串:一個使用PARSENAME *

快速免責聲明2

使用傑夫MODEN的DelimitedSplit8K,其他的技術我應該鏈接該列插入指出一個問題作爲一對夫婦建議的單個字符串 - 它可能導致誤報;考慮下面的查詢:

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 '%'[email protected]+'%'; 

上面的查詢將返回即使「AB」並不在任一列中存在的第一個記錄。出於這個原因,你會改變(在約翰的例子或CHARINDEX)在哪裏找這樣的:

WHERE CONCAT(fn, '|||', ln) LIKE '%'[email protected]+'%'; 

我的解決方案

-- 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; 
+0

組合列的想法是可怕的。這會導致性能下降。正如我在我的評論中提到的 –

+0

@ t-clausen.dk - 這就是爲什麼我說「全文搜索可能是最好的解決方案」,然後補充說我包括一個T-SQL解決方案「爲了好玩」。你提供的只是一個評論,包括OP在內的每個人都已經知道。我會對你發佈的解決方案感興趣.... –

+0

你實際上是投我的[回覆](http://stackoverflow.com/questions/42509024/get-string-between-2-characters-that-重複 - 幾次在SQL服務器/ 42509706#comment72537334_42509706)復仇的另一個問題,我投下了這個投票? –