编辑 - 如果可能,首选基于 LINQ 的 ORM
如果您不需要在 ADO 中执行此操作,更好的解决方案是使用 ORM,它最终将构建参数化的 ad-hoc sql。这是两全其美的方式——您可以获得动态查询的灵活性,没有多余的过滤器会扰乱优化器,查询计划本身是可缓存的,并且您可以免受注入攻击等恶意攻击。基于 Linq 的 ORM 查询使阅读更容易:
// Build up a non-materialized IQueryable<>
var usersQuery = db.Users;
if (!string.IsNullOrEmpty(userID))
{
usersQuery = usersQuery.Where(u => u.Name == userId);
}
// Of course, you wouldn't dream of storing passwords in cleartext.
if (!string.IsNullOrEmpty(anotherField))
{
usersQuery = usersQuery.Where(u => u.AnotherColumn == anotherField);
}
...
// Materialize (and execute) the query
var filteredUsers = usersQuery.ToList();
对于复杂的查询,您可能需要查看PredicateBuilder
ADO/手动查询构建
您可以使用sp_executesql
以下方法动态构建 SQL。如果您参数化变量,您应该可以避免 SQL 注入和转义引号等问题,我们将为您处理。
CREATE PROCEDURE [dbo].[PROC001]
@userID varchar(20),
@pwdHash varchar(20),
@optionalParam1 NVARCHAR(50) = NULL -- Other optional parameters
AS
BEGIN
SET NOCOUNT ON
DECLARE @SQL NVARCHAR(MAX)
-- Mandatory / Static part of the Query here.
-- Cleartext passwords are verboten, and RTRIM is redundant in filters
SET @SQL = N'SELECT * FROM tUsers WHERE Name = @userID AND PwdHash = @pwdHash'
IF @OptionalParam1 IS NOT NULL
BEGIN
SET @SQL = @SQL + N' AND AnotherField = @OptionalParam1'
END
EXEC sp_executesql @SQL,
N'@userID varchar(20),
@pwdHash varchar(20),
@optionalParam1 NVARCHAR(50)'
,@userID = @userID
,@pwdHash = @pwdHash
,@optionalParam1 = @optionalParam1
END
重新,为什么是WHERE (@x IS NULL OR @x = Column)
一个坏主意?
(来自我下面的评论)
尽管“可选参数”模式在小表上使用时可以很好地作为“瑞士军刀”查询可选过滤器的多种排列,但不幸的是,对于大表,这会导致针对所有过滤器排列的单个查询计划查询,由于参数嗅探问题,这可能导致可选参数的某些排列的查询性能不佳。如果可能,您应该完全消除冗余过滤器。
回复:为什么在谓词中应用函数是个坏主意
例如
WHERE SomeFunction(Column) = @someParameter
在谓词中使用函数经常会取消 RDBMS 对索引的使用(“non-sargable”)。
在这种情况下,RTRIM
是不必要的,因为 Sql server在比较过程中会忽略尾随空格。