Как указать «DEFAULT» в качестве значения параметра SQL в ADO.NET?
-
24-10-2019 - |
Вопрос
У меня есть параметризованный SQL-запрос, предназначенный для SQL2005, который динамически создается в коде, поэтому я использовал ADO.NET. SqlParameter
класс для добавления параметров sql SqlCommand
.
В вышеупомянутом SQL я выбираю функцию с табличным значением и имеет значения по умолчанию.Я хочу, чтобы мой динамический SQL иногда указывал значение для этих параметров по умолчанию, а иногда я хочу указать, что SQL DEFAULT
- как определено в табличной функции - следует использовать.
Чтобы сохранить код чистый Я не хотел динамически добавлять SQL DEFAULT
ключевое слово и параметризовать его, если нужно использовать значение, отличное от значения по умолчанию, я просто хотел установить DEFAULT
как ценность моего SQLParameter
.
Могу я?Какова наилучшая практика в таком случае?
Решение
Параметры SQL-запроса заменяют литеральные значения. только.
Вы не можете отправить ключевое слово SQL в качестве значения параметра, так же как вы не можете отправить идентификатор таблицы, идентификатор столбца, список значений (например,для IN
предикат) или выражение.Значение параметра всегда интерпретируется как буквальное значение, как если бы вы включили в свой запрос строковый или числовой литерал в кавычках.
Извините, но вам необходимо включить ключевое слово SQL как часть запроса SQL. до вы готовите этот запрос.
Другие советы
AFAIK, единственный способ указать SQL Server использовать значение по умолчанию - через DEFAULT
ключевое слово или исключить его из списка параметров.Это означает, что использование DEFAULT
Ключевое слово должно быть в параметризованном операторе SQL.Итак, что-то вроде:
Select ...
From dbo.udf_Foo( DEFAULT, @Param2, @Param3, DEFAULT, .... )
Я полагаю, что другим подходом было бы запросить в системных каталогах фактическое значение различных DEFAULT
значения и определить, следует ли таким образом устанавливать для SqlParameter значение по умолчанию, но для получения значений по умолчанию требуется сложный второй запрос.
Если у вас есть следующая функция (например):
CREATE FUNCTION dbo.UFN_SAMPLE_FUNCTION
(
@Param1 nvarchar(10),
@Param2 int = NULL
)
RETURNS TABLE
AS
RETURN
SELECT @Param1 AS Col1, @Param2 AS Col2;
GO
Тогда вы можете использовать его следующим образом (вариант 1):
SELECT * FROM dbo.UFN_SAMPLE_FUNCTION ('ABC', DEFAULT);
это правильный путь, и вы получите следующий результат:
Col1 Col2
---------- -----------
ABC NULL
Но если вы попытаетесь использовать параметризованный запрос (вариант 2):
exec sp_executesql N'SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (@P1, @P2)',N'@P1 nvarchar(10),@P2 int',@P1=N'abc',@P2=default;
вы получите ошибку:
Msg 8178, Level 16, State 1, Line 0
The parameterized query '(@P1 nvarchar(10),@P2 int)SELECT * FROM dbo.UFN_SAMPLE_FUNCTION' expects the parameter '@P2', which was not supplied.
Если у вас есть следующий код .net:
public void RunTVF(string param1, int? param2)
{
using (SqlConnection con = GetProdConection())
{
using (var cmd = new SqlCommand("SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (@P1, @P2)", con))
{
cmd.CommandType = CommandType.Text;
var param = new SqlParameter
{
ParameterName = "@P1",
SqlDbType = SqlDbType.NVarChar,
Size = 10 ,
Value = param1
};
cmd.Parameters.Add(param);
param = new SqlParameter
{
ParameterName = "@P2",
SqlDbType = SqlDbType.Int,
Value = param2
};
cmd.Parameters.Add(param);
cmd.Connection.Open();
using (IDataReader dataReader = cmd.ExecuteReader())
{
//...
}
}
}
}
тогда, если param2 = null, как предложил Джек выше, сценарий, созданный кодом, будет идентичен варианту 2 и приведет к той же ошибке.Поэтому вы не можете использовать НУЛЕВОЙ в этом случае. Вы не можете установить ПО УМОЛЧАНИЮ как значение SQLParameter.
Что вы можете сделать, так это создать хранимую процедуру для переноса вызова вашей функции и перемещения значения по умолчанию из функции в SP.Пример:
CREATE PROCEDURE dbo.USP_SAMPLE_PROCEDURE
(
@Param1 nvarchar(10),
@Param2 int = NULL, --DEFAULT value now is here (remove it from the function)
@Statement nvarchar(max)
)
AS
BEGIN
SET NOCOUNT ON;
EXEC sp_executesql @Statement,N'@P1 nvarchar(10),@P2 int',@P1=@Param1,@P2=@Param2;
END
Код .NET будет выглядеть следующим образом:
public void RunWrapper(string param1, int? param2)
{
using (SqlConnection con = GetProdConection())
{
using (var cmd = new SqlCommand("USP_SAMPLE_PROCEDURE", con))
{
cmd.CommandType = CommandType.StoredProcedure;
var param = new SqlParameter
{
ParameterName = "@Param1",
SqlDbType = SqlDbType.NVarChar,
Size = 10,
Value = param1
};
cmd.Parameters.Add(param);
param = new SqlParameter
{
ParameterName = "@Param2",
SqlDbType = SqlDbType.Int,
Value = param2
};
cmd.Parameters.Add(param);
param = new SqlParameter
{
ParameterName = "@Statement",
SqlDbType = SqlDbType.NVarChar,
Size = -1, //-1 used in case you need to specify nvarchar(MAX)
Value = "SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (@P1, @P2)"
};
cmd.Parameters.Add(param);
cmd.Connection.Open();
using (IDataReader dataReader = cmd.ExecuteReader())
{
//...
}
}
}
}
В этом случае нулевой как ценность для параметр2 будет переведено на правильный ПО УМОЛЧАНИЮ и будет создан следующий скрипт:
exec USP_SAMPLE_PROCEDURE @Param1=N'ABC',@Param2=default,@Statement=N'SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (@P1, @P2)'
что даст вам следующий результат:
Col1 Col2
---------- -----------
ABC NULL
Я не уверен, что это лучшая практика.Это всего лишь обходной путь.
Хотя вы не можете установить ключевое слово SQL в качестве значения параметра, в этом случае вы можете пойти и получить ЗНАЧЕНИЕ ПО УМОЛЧАНИЮ.
SELECT COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table_name' AND COLUMN_NAME = 'column_name'"
Если вы передадите нулевое значение точечного числа в качестве значения параметра, оно будет использовать SQL Default, если вы передаете точечный сетевой dbnull.value, он будет использовать SQL NULL