仅当用户输入值时按参数搜索

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 值?

HTML5 表单验证

javascript:在用户键入或更改文本框值时忽略无效输入[重复]

当并行用户输入文本字段值更改下拉值时,应自动更改

用户在PEGA中输入值时,检查数据库中是否已存在用户名