仅当用户输入值时按参数搜索
Posted
技术标签:
【中文标题】仅当用户输入值时按参数搜索【英文标题】:Search by parameter only if user enters a value 【发布时间】:2009-02-13 20:45:14 【问题描述】:我想重写此查询,以便如果 @UserName 传入一个空值,那么它将 Client_User 排除在搜索条件之外。如果用户在网络表单的用户名文本框中输入名称,我只希望它按名称搜索。我不知道该怎么做。
select * from weblogs.dbo.vwlogs
where Log_time between @BeginDate and @EndDAte
and client_user=@UserName
【问题讨论】:
【参考方案1】:从 weblogs.dbo.vwlogs 中选择 *,其中 @BeginDate 和 @EndDate 之间的 Log_time 和 (@UserName 为 NULL 或 client_user=@UserName)
【讨论】:
【参考方案2】:select *
from weblogs.dbo.vwlogs
where Log_time between @BeginDate and @EndDAte
and (client_user=@UserName or @UserName IS null)
【讨论】:
@UserName IS NULL 而不是@UserName = NULL 除非“SET ANSI_NULLS = OFF”——恕我直言,这是魔鬼的杰作!【参考方案3】:Kristen 的解决方案可行,但如果您需要性能,请不要这样做,因为该计划将仅针对第一个条件进行缓存。
因此,如果首先使用 NULL 参数调用您的过程,则该查询将被缓存。
如果您需要更高的性能,请使用 IF 语句并创建两个不同的查询。
在更复杂的查询中,事件 sp_execsql 会更快。
【讨论】:
我同意,但是如果代码在存储过程中,那么参数嗅探可能会有所帮助......如果它只是动态 SQL,那么所有关于缓存的赌注无论如何都不会发生 - 或者,正如你所说,最好还是使用带有显式生成的 WHERE 子句的 sp_ExecuteSQL,以便单独缓存每个变体 是的,无论如何,你的答案是对的,我已经升级了。我的回答只是附加信息...【参考方案4】:最好的解决方案是利用 sp_execute_sql。例如:
--BEGIN SQL
declare @sql nvarchar(4000)
set @sql =
'select * from weblogs.dbo.vwlogs
where Log_time between @BeginDate and @EndDate'
+ case when @UserName is null then '' else 'and client_user = @UserName' end
sp_execute_sql
@sql
, @params = '@UserName varchar(50)'
, @UserName = @UserName
--END SQL
正如 muerte 所说,这将带来性能优势。根据 BOL:
当参数值对语句的更改是唯一的变化时,可以使用 sp_executesql 代替存储过程多次执行 Transact-SQL 语句。因为 Transact-SQL 语句本身保持不变并且只有参数值发生变化,所以 Microsoft® SQL Server™ 查询优化器可能会重用它为第一次执行生成的执行计划。
【讨论】:
嗯,这对于 2 个参数来说可能是矫枉过正。不过,当你有更多时很有用。 像这样:***.com/questions/532468/… 不确定 2 个参数的过度杀伤力。为“@UserName IS NULL OR COL=@UserName”SProc 缓存的查询计划将基于其首次使用。这可能会破坏替代 @UserName 存在/不存在场景的性能。 sp_ExecuteSQL 直接从 APP 可能是最好的 - 但仍需要 SELECT 权限以上是关于仅当用户输入值时按参数搜索的主要内容,如果未能解决你的问题,请参考以下文章
仅当非空值时,如何在输入和过滤数据中具有默认的 NULL 值?