如何在 T-SQL 存储过程中使用可选参数?
我正在创建一个存储过程来搜索表。我有许多不同的搜索字段,所有这些都是可选的。有没有办法创建一个存储过程来处理这个问题?假设我有一个包含四个字段的表:ID、FirstName、LastName 和 Title。我可以做这样的事情:
CREATE PROCEDURE spDoSearch
@FirstName varchar(25) = null,
@LastName varchar(25) = null,
@Title varchar(25) = null
AS
BEGIN
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
FirstName = ISNULL(@FirstName, FirstName) AND
LastName = ISNULL(@LastName, LastName) AND
Title = ISNULL(@Title, Title)
END
这种工作。但是,它会忽略 FirstName、LastName 或 Title 为 NULL 的记录。如果搜索参数中未指定标题,我想包含标题为 NULL 的记录 - 名字和姓氏相同。我知道我可以使用动态 SQL 来做到这一点,但我想避免这种情况。
I am creating a stored procedure to do a search through a table. I have many different search fields, all of which are optional. Is there a way to create a stored procedure that will handle this? Let's say I have a table with four fields: ID, FirstName, LastName and Title. I could do something like this:
CREATE PROCEDURE spDoSearch
@FirstName varchar(25) = null,
@LastName varchar(25) = null,
@Title varchar(25) = null
AS
BEGIN
SELECT ID, FirstName, LastName, Title
FROM tblUsers
WHERE
FirstName = ISNULL(@FirstName, FirstName) AND
LastName = ISNULL(@LastName, LastName) AND
Title = ISNULL(@Title, Title)
END
This sort of works. However it ignores records where FirstName, LastName or Title are NULL. If Title is not specified in the search parameters I want to include records where Title is NULL - same for FirstName and LastName. I know I could probably do this with dynamic SQL but I would like to avoid that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
根据给定参数动态改变搜索是一个复杂的主题,并且以一种不同的方式进行,即使只有非常微小的差异,也会产生巨大的性能影响。关键是使用索引,忽略紧凑的代码,忽略重复代码的担忧,必须制定好的查询执行计划(使用索引)。
阅读本文并考虑所有方法。您的最佳方法将取决于您的参数、数据、架构和实际使用情况:
动态搜索条件在 T-SQL 中,作者:Erland Sommarskog
动态 SQL 的诅咒与祝福,作者:Erland Sommarskog
如果您有正确的 SQL Server 2008 版本(SQL 2008 SP1 CU5 (10.0.2746) 及更高版本),您可以使用这个小技巧来实际使用索引:
将
OPTION (RECOMPILE)
添加到您的查询,参见 Erland 的文章,SQL Server 将解析在基于局部变量的运行时值创建查询计划之前,从
,并且可以使用索引。(@LastName IS NULL OR LastName= @LastName)
中执行 OR这适用于任何 SQL Server 版本(返回正确的结果),但仅当您使用 SQL 2008 SP1 CU5 (10.0.2746) 及更高版本时才包含选项(RECOMPILE)。 OPTION(RECOMPILE) 将重新编译您的查询,只有列出的版本才会根据局部变量的当前运行时值重新编译它,这将为您提供最佳性能。如果不在该版本的 SQL Server 2008 上,则将该行保留为关闭。
Dynamically changing searches based on the given parameters is a complicated subject and doing it one way over another, even with only a very slight difference, can have massive performance implications. The key is to use an index, ignore compact code, ignore worrying about repeating code, you must make a good query execution plan (use an index).
Read this and consider all the methods. Your best method will depend on your parameters, your data, your schema, and your actual usage:
Dynamic Search Conditions in T-SQL by by Erland Sommarskog
The Curse and Blessings of Dynamic SQL by Erland Sommarskog
If you have the proper SQL Server 2008 version (SQL 2008 SP1 CU5 (10.0.2746) and later), you can use this little trick to actually use an index:
Add
OPTION (RECOMPILE)
onto your query, see Erland's article, and SQL Server will resolve theOR
from within(@LastName IS NULL OR LastName= @LastName)
before the query plan is created based on the runtime values of the local variables, and an index can be used.This will work for any SQL Server version (return proper results), but only include the OPTION(RECOMPILE) if you are on SQL 2008 SP1 CU5 (10.0.2746) and later. The OPTION(RECOMPILE) will recompile your query, only the verison listed will recompile it based on the current run time values of the local variables, which will give you the best performance. If not on that version of SQL Server 2008, just leave that line off.
@KM 的答案就目前而言是好的,但未能完全遵循他早期的建议之一;
如果您希望获得最佳性能,那么您应该为可选条件的每个可能组合编写一个定制查询。这听起来可能很极端,如果您有很多可选标准,那么它可能会很极端,但性能通常是努力和结果之间的权衡。在实践中,可能存在一组通用的参数组合,可以针对定制查询,然后针对所有其他组合进行通用查询(根据其他答案)。
这种方法的优点是,在定制查询处理的常见情况下,查询尽可能高效 - 不受未提供的条件的影响。此外,索引和其他性能增强可以针对特定的定制查询,而不是试图满足所有可能的情况。
The answer from @KM is good as far as it goes but fails to fully follow up on one of his early bits of advice;
If you are looking to achieve the best performance then you should write a bespoke query for each possible combination of optional criteria. This might sound extreme, and if you have a lot of optional criteria then it might be, but performance is often a trade-off between effort and results. In practice, there might be a common set of parameter combinations that can be targeted with bespoke queries, then a generic query (as per the other answers) for all other combinations.
The advantage of this approach is that in the common cases handled by bespoke queries the query is as efficient as it can be - there's no impact by the unsupplied criteria. Also, indexes and other performance enhancements can be targeted at specific bespoke queries rather than trying to satisfy all possible situations.
您可以在以下情况下执行此操作,
但是有时取决于数据,更好地创建动态查询并执行它们。
You can do in the following case,
however depend on data sometimes better create dynamic query and execute them.
聚会迟到了五年。
它在所接受的答案的提供的链接中提到,但我认为它值得在 SO 上有一个明确的答案 - 根据提供的参数动态构建查询。例如:
设置
过程
使用
优点:
缺点:
不是直接答案,但与问题(又名大局)相关
通常,这些过滤存储过程不会浮动,而是从某个服务层调用。这就留下了将业务逻辑(过滤)从 SQL 移至服务层的选项。
一个示例是使用 LINQ2SQL 根据提供的过滤器生成查询:
优点:
缺点:
Five years late to the party.
It is mentioned in the provided links of the accepted answer, but I think it deserves an explicit answer on SO - dynamically building the query based on provided parameters. E.g.:
Setup
Procedure
Usage
Pros:
Cons:
Not direct answer, but related to the problem aka the big picture
Usually, these filtering stored procedures do not float around, but are being called from some service layer. This leaves the option of moving away business logic (filtering) from SQL to service layer.
One example is using LINQ2SQL to generate the query based on provided filters:
Pros:
Cons:
扩展您的
WHERE
条件:即将不同的情况与布尔条件结合起来。
Extend your
WHERE
condition:i. e. combine different cases with boolean conditions.
这也有效:
This also works: