Как вы определяете "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