Neater SQL Query用于处理可选的WHERE子句过滤器

时间:2011-10-12 07:40:23

标签: sql sql-server-2005 tsql syntax

请参阅下面的SQL语句:

有没有更好的方法来消除案例陈述?

select * from Customer 
where FirstName like ISNULL('ja','') + '%'  
AND [EmailId] LIKE ISNULL('jaisonshereen@gmail.com1','') 
    + CASE when 'jaisonshereen@gmail.com1' =  '' then '%' else ''  end

1 个答案:

答案 0 :(得分:1)

基于@ Thor84no的观察,我已经参数化了你的查询(假设它是代码生成的)并且假设了以下要求:

  • @Firstname和@Email都是可选的
  • 如果@Firstname不为null或为空,则始终以%为后缀并执行类似操作,否则应用虚拟过滤器(LIKE'%')
  • 如果@Email不为空或空白,则执行精确搜索(如@EMAIL),否则应用虚拟过滤器(LIKE'%')

所以它的参数设置如下:

DECLARE @FirstName NVARCHAR(100)
DECLARE @EmailId NVARCHAR(100)
SET @FirstName = 'ja'
SET @EmailId = 'jaisonshereen@gmail.com1'

select * from Customer 
where FirstName like ISNULL(@FirstName,'') + N'%'  
AND [EmailId] LIKE ISNULL(@EmailId, N'') 
    + CASE when @EmailId =  N'' then N'%' else N''  end

我相信有一种情况你不会处理,即如果@Email为NULL - 你需要将最后一行更改为

+ CASE when IsNull(@EmailId, '') =  N'' then N'%' else N''  end

你的代码的查询计划相当不错 - 它总是WHERE FirstName LIKE'..%'和EMailId喜欢'..'(或EmailId喜欢'%') - 这可能是代码生成器执行此操作的原因。

虽然为了便于阅读而尝试以下操作很有诱惑力,但“OR”会影响查询计划,并且通常会导致表/索引扫描

select * from Customer 
WHERE 
(ISNULL(@FirstName, N'') = N'' OR FirstName LIKE @FirstName + N'%')
AND (ISNULL(@EmailId, N'') = N'' OR [EmailId] = @EmailId) -- Assuming ANSI Nulls are ON

因此,虽然你看起来很乱,但它实际上是非常理想的。

出于兴趣,动态SQL(例如由LINQ2SQL,EF等ORMS生成)在大量参数可选的情况下通常比存储过程具有优势。 通过使用参数化SQL,仍可以缓存查询计划,并且可以防止查询受到SQL注入攻击。比较

DECLARE @FirstName NVARCHAR(100)
DECLARE @EmailId NVARCHAR(100)
SET @FirstName = 'ja'
SET @EmailId = 'jaisonshereen@gmail.com1'

DECLARE @SQL NVARCHAR(MAX)
SET @SQL = N'SELECT * FROM Customer '

IF ISNULL(@FirstName,'') <> N'' OR ISNULL(@EmailId, N'') <> N''
    SET @SQL = @SQL + N'WHERE ' -- Need to handle the case where neither param provided

IF ISNULL(@FirstName, N'') <> N''
    SET @SQL = @SQL + N' FirstName LIKE @FirstName + ''%'''

IF ISNULL(@FirstName,'') <> N'' AND ISNULL(@EmailId, N'') <> N''
    SET @SQL = @SQL + N' AND'

IF ISNULL(@EmailId,'') <> N''
    SET @SQL = @SQL + N' EmailId = @EmailId' -- Exact match

exec sp_ExecuteSQL @SQL, N'@FirstName NVARCHAR(100), @EmailId NVARCHAR(100)', @FirstName=@FirstName, @EmailId=@EmailId