2012-03-26 79 views
2

比方說,我有這樣一個表:跨多個列搜索實施

Persons 
    FirstName varchar(50) 
    LastName varchar(50) 
    EmailAddress varchar(200) 

現在,讓我們說我有一個搜索框,一個谷歌;換句話說,只有一個帶有搜索按鈕的文本框。

通常我們做這樣的事情:

declare @searchTerm varchar(50) 
set @searchTerm = 'tom' 

select * 
    from Persons 
    where (FirstName = @searchTerm) 
    or (LastName = @searchTerm) 
    or (EmailAddress = @searchTerm) 

我希望做的是能夠在第一和最後一個名稱(例如)通入@searchTerm變量,但我的大腦只是沒有按不想構建該查詢。 ;)

例如:

​​

的想法是返回,其中「嗵」或「鐵匠」出現在這些領域中的所有記錄。

回答

5

這是一個非常複雜的話題,具有許多微妙的性能影響。你真的需要通過厄蘭Sommarskog閱讀這些優秀的文章:

Dynamic Search Conditions in T-SQL

The Curse and Blessings of Dynamic SQL

既然沒有「一刀切」這種查詢方法,也有細微的性能影響你該怎麼辦這個。如果您想超越只是讓查詢返回正確的答案,不管它有多慢,看看這篇文章:Dynamic Search Conditions in T-SQL by Erland Sommarskog。它涵蓋了每種方法,並且非常詳細地給出了每種方法的PRO和Cons。

如果您可以確定搜索列的最小和最大可能範圍,並且搜索列不是NULL,那麼您可以比(@Search IS NULL或Col = @ Search),see this area of the above linked article做得更好。不過,你應該閱讀整篇文章,有很多變化取決於你的情況,你真的需要學習多種方法以及何時使用它們。

如果您想在單個字符串參數中搜索多個術語,則需要拆分該字符串。

您需要創建一個拆分功能。這是一個分裂的功能如何使用:

SELECT 
    * 
    FROM YourTable        y 
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value 

I prefer the number table approach to split a string in TSQL但也有許多方法來拆分在SQL Server中的字符串,見前面的鏈接,這說明各的優點和缺點。

對於數字表的方法來工作,你需要做的這一次表的設置,這將創建一個包含從1到10000行的表Numbers

SELECT TOP 10000 IDENTITY(int,1,1) AS Number 
    INTO Numbers 
    FROM sys.objects s1 
    CROSS JOIN sys.objects s2 
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number) 

一旦Numbers表格設置,創建此分割功能:

CREATE FUNCTION [dbo].[FN_ListToTable] 
(
    @SplitOn char(1)  --REQUIRED, the character to split the @List string on 
    ,@List  varchar(8000)--REQUIRED, the list to split apart 
) 
RETURNS TABLE 
AS 
RETURN 
(

    ---------------- 
    --SINGLE QUERY-- --this will not return empty rows 
    ---------------- 
    SELECT 
     ListValue 
     FROM (SELECT 
        LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue 
        FROM (
          SELECT @SplitOn + @List + @SplitOn AS List2 
         ) AS dt 
         INNER JOIN Numbers n ON n.Number < LEN(dt.List2) 
        WHERE SUBSTRING(List2, number, 1) = @SplitOn 
      ) dt2 
     WHERE ListValue IS NOT NULL AND ListValue!='' 

); 
GO 

您現在可以輕鬆地拆分CSV字符串轉換成表格,並加入就可以了:

select * from dbo.FN_ListToTable(',','1,2,3,,,4,5,6777,,,') 

OUTPUT:

ListValue 
----------------------- 
1 
2 
3 
4 
5 
6777 

(6 row(s) affected) 

您可以使用多個搜索標準字符串是這樣的:

DECLARE @Persons table (FirstName varchar(50) , LastName varchar(50), EmailAddress varchar(200)) 
INSERT INTO @Persons VALUES ('aaa','bbb','[email protected]') 
INSERT INTO @Persons VALUES ('xxx','yyy','[email protected]') 
INSERT INTO @Persons VALUES ('aaa','yyy','[email protected]') 
INSERT INTO @Persons VALUES ('111','222','[email protected]') 

declare @searchTerm varchar(50) 
set @searchTerm = 'aaa bbb' 

--this should use an index on FirstName and LastName if they exist, no index usage on EmailAddress 
select 
    p.* --<<"*" isn't good, only list the columns you need 
    FROM @Persons          p 
     INNER JOIN dbo.FN_ListToTable(' ',@searchTerm) b on p.FirstName=b.Listvalue 
UNION 
select 
    p.* --<<"*" isn't good, only list the columns you need 
    FROM @Persons          p 
     INNER JOIN dbo.FN_ListToTable(' ',@searchTerm) b on p.LastName=b.Listvalue 
UNION 
select 
    p.* --<<"*" isn't good, only list the columns you need 
    FROM @Persons          p 
     INNER JOIN dbo.FN_ListToTable(' ',@searchTerm) b on p.EmailAddress like '%'+b.Listvalue+'%' 

OUTPUT:

FirstName LastName EmailAddress 
---------- ---------- ------------------------- 
aaa  bbb  [email protected] 
aaa  yyy  [email protected] 
xxx  yyy  [email protected] 

(3 row(s) affected) 

這種方法適用於任何數量的參數工作:

aaa 
aaa 
aaa bbb 
aaa bbb 
aaa bbb eee 
aaa bbb eee ddd 
aaa bbb eee 
0

你可以試試這樣:

DECLARE 
    @searchTerm VARCHAR(100), 
    @FirstName VARCHAR(100), 
    @LastName VARCHAR(100) 
SET 
    @searchTerm = 'tom smith' 

SELECT 
    @FirstName = '%' + SUBSTRING(@searchTerm, 1, CHARINDEX(' ', @searchTerm) - 1) + '%', 
    @LastName = '%' + SUBSTRING(@searchTerm, CHARINDEX(' ', @searchTerm) + 1, LEN(@searchTerm)) + '%' 

SELECT * 
FROM 
    Persons 
WHERE 
    FirstName LIKE @FirstName 
OR LastName LIKE @FirstName 
OR EmailAddress LIKE @FirstName 
OR FirstName LIKE @LastName 
OR LastName LIKE @LastName 
OR EmailAddress LIKE @LastName