Как вы определяете "DEFAULT" как значение параметра SQL в ADO.NET?
У меня есть параметризованный SQL-запрос, предназначенный для SQL2005, который динамически создается в коде, поэтому я использовал класс ADO.NET SqlParameter
для добавления sql-параметров в SqlCommand
.
В вышеупомянутом SQL я выбираю из таблицы Valued Function с параметрами по умолчанию. Я хочу, чтобы мой динамический sql иногда указывал значение для этих параметров по умолчанию, а в других случаях я хочу указать, что SQL DEFAULT
- как определено в Табличной значащей функции - должен использоваться.
Чтобы сохранить код в чистоте, я не хотел динамически добавлять ключевое слово SQL DEFAULT
и параметризовать его, когда используется нестандартный, я просто хотел установить DEFAULT
как значение моего SqlParameter
.
Могу ли я? Какова наилучшая практика в таком случае?
Ответы
Ответ 1
Параметры запроса SQL заменяют только литеральные значения.
Вы не можете отправить ключевое слово SQL в качестве значения параметра, так же как вы не можете отправить идентификатор таблицы, идентификатор столбца, список значений (например, для предиката IN
) или выражение. Значение параметра всегда интерпретируется как буквальное значение, как если бы вы включили цитированный строковый литерал или числовой литерал в свой запрос.
Извините, но вы должны включить ключевое слово SQL как часть SQL-запроса, прежде чем подготовить этот запрос.
Ответ 2
AFAIK, единственный способ сказать SQL Server использовать значение по умолчанию - через ключевое слово DEFAULT
или исключить его из списка параметров. Это означает, что использование ключевого слова DEFAULT
должно быть в параметризованном SQL-заявлении. Итак, что-то вроде:
Select ...
From dbo.udf_Foo( DEFAULT, @Param2, @Param3, DEFAULT, .... )
Я предполагаю, что другой подход состоял бы в том, чтобы запросить системные каталоги для фактического значения различных значений DEFAULT
и определить, следует ли устанавливать SqlParameter на значение по умолчанию таким образом, но для этого требуется свернутый второй запрос для получения значения по умолчанию значения.
Ответ 3
Если у вас есть следующая функция (например):
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, как предложено выше, Jack script, созданный кодом, будет идентичен параметру 2 и приведет к той же ошибке. Таким образом, вы не можете использовать NULL в этом случае. Вы не можете установить DEFAULT как значение 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',@[email protected],@[email protected];
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())
{
//...
}
}
}
}
В этом случае значение null как значение для параметра param2 будет переведено на правильный DEFAULT, и будет создано следующее script:
exec USP_SAMPLE_PROCEDURE @Param1=N'ABC',@Param2=default,@Statement=N'SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (@P1, @P2)'
который даст вам следующий результат:
Col1 Col2
---------- -----------
ABC NULL
Я не уверен, что это лучшая практика. Это просто работа.
Ответ 4
Хотя вы не можете установить ключевое слово SQL в качестве значения параметра, вы могли бы в этом случае пойти и получить ЗНАЧЕНИЕ ПО УМОЛЧАНИЮ.
SELECT COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table_name' AND COLUMN_NAME = 'column_name'"
Ответ 5
если вы передадите значение net net null в качестве значения параметра, которое будет использовать sql DEFAULT
если вы передадите dot net DBNull.Value, он будет использовать sql NULL