Как указать «DEFAULT» в качестве значения параметра SQL в ADO.NET?

StackOverflow https://stackoverflow.com/questions/2970516

Вопрос

У меня есть параметризованный 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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top