Ответ 1
Изменить - предпочтение ORM на основе LINQ, если возможно
Если вам не нужно делать это в ADO, лучшим решением будет использовать ORM, который в конечном итоге будет создавать параметризованный ad-hoc sql. Это лучшее из обоих миров - вы получаете гибкость динамического запроса, без избыточных фильтров, чтобы расстроить оптимизатор, сам план запроса можно кэшировать, и вы можете быть в безопасности от настиг, таких как инъекции. И запрос ORM на основе Linq упрощает чтение:
// 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),
@password 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
Re, почему WHERE (@x IS NULL OR @x = Column)
плохая идея?
(Из моего комментария ниже)
Хотя шаблон "необязательного параметра" хорошо работает как "швейцарский армейский нож" для запроса множества перестановок дополнительных фильтров при использовании на небольших таблицах, к сожалению, для больших таблиц это приводит к единому плану запроса для всех перестановок фильтров для запроса, что может привести к низкой производительности запросов с некоторыми перестановками необязательных параметров из-за проблемы с параметром . Если возможно, вы должны полностью исключить избыточные фильтры.
Re: Почему применение предикатов в плохих идеях
например.
WHERE SomeFunction(Column) = @someParameter
Использование функций в предикатах часто дисквалифицирует использование индексов с помощью СУБД ( "non-sargable" ).
В этом случае RTRIM
не требуется, поскольку сервер Sql игнорирует конечные пробелы во время сравнения.