简体   繁体   English

如何在ADO.NET中将“DEFAULT”指定为SQL参数值?

[英]How do you specify 'DEFAULT' as a SQL parameter value in ADO.NET?

I have a parameterized SQL query targetted for SQL2005 which is dynamically created in code, so I used the ADO.NET SqlParameter class to add sql parameters to SqlCommand . 我有一个针对SQL2005的参数化SQL查询,它是在代码中动态创建的,所以我使用ADO.NET SqlParameter类将sql参数添加到SqlCommand

In the aforementioned SQL I select from a Table Valued Function with has defaults. 在前面提到的SQL中,我从具有默认值的表值函数中进行选择。 I want my dynamic sql to sometimes specify a value for these default parameters, and other times I want to specify that the SQL DEFAULT - as defined in the Table Valued Function - should be used. 我希望我的动态sql有时为这些默认参数指定一个值,有时我想指定应该使用SQL DEFAULT - 如表值函数中定义的那样。

To keep the code clean I didn't want to dynamically add the SQL DEFAULT keyword and parameterize it when a non-default is to be used, I just wanted to set DEFAULT as the value of my SQLParameter . 为了保持代码清洁,我不想动态添加SQL DEFAULT关键字并在使用非默认值时对其进行参数化,我只想将DEFAULT设置为我的SQLParameter的值。

Can I? 我可以吗? What is best practice in such an instance? 在这种情况下,最佳做法是什么?

SQL query parameters take the place of literal values only . SQL查询参数取代文字值。

You can't send an SQL keyword as the value of a parameter, just as you cannot send a table identifier, column identifier, list of values (eg for an IN predicate), or an expression. 您不能将SQL关键字作为参数的值发送,就像您无法发送表标识符,列标识符,值列表(例如,对于IN谓词)或表达式一样。 The value of the parameter is always interpreted as a literal value, as if you had included a quoted string literal or a numeric literal in your query. 参数的值始终被解释为文字值,就像您在查询中包含带引号的字符串文字或数字文字一样。

Sorry, but you have to include an SQL keyword as part of the SQL query before you prepare that query. 抱歉,您必须准备该查询之前将SQL关键字包含在SQL查询中。

AFAIK, the only way to tell SQL Server to use a default value is via the DEFAULT keyword or to exclude it from parameter list. AFAIK,告诉SQL Server使用默认值的唯一方法是通过DEFAULT关键字或从参数列表中排除它。 That means that the use of the DEFAULT keyword must be in your parameterized SQL Statement. 这意味着DEFAULT关键字的使用必须在参数化的SQL语句中。 So, something like: 所以,像:

Select ...
From dbo.udf_Foo( DEFAULT, @Param2, @Param3, DEFAULT, .... )

I suppose another approach would be to query the system catalogs for the actual value of the various DEFAULT values and determine whether to set the SqlParameter to the default value that way, but that requires a convoluted second query to get the default values. 我想另一种方法是查询系统目录中各种DEFAULT值的实际值,并确定是否将SqlParameter设置为默认值,但这需要一个复杂的第二个查询来获取默认值。

If you have the following function (for example): 如果您具有以下功能(例如):

CREATE FUNCTION dbo.UFN_SAMPLE_FUNCTION 
(
    @Param1 nvarchar(10), 
    @Param2 int = NULL
)
RETURNS TABLE
AS 
RETURN 
   SELECT @Param1 AS Col1, @Param2 AS Col2;
GO

Then you can use it the following way (option 1): 然后您可以通过以下方式使用它(选项1):

SELECT * FROM dbo.UFN_SAMPLE_FUNCTION ('ABC', DEFAULT);

which is correct way and you get the following result: 这是正确的方法,你得到以下结果:

Col1       Col2
---------- -----------
ABC        NULL

But if you try to use parametrized query (option 2): 但是,如果您尝试使用参数化查询(选项2):

exec sp_executesql N'SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (@P1, @P2)',N'@P1 nvarchar(10),@P2 int',@P1=N'abc',@P2=default;

you will get an error: 你会收到一个错误:

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.

If you have the following .net code: 如果您有以下.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())
            {
                //...
            }
        }
    }
}

then, in case param2 = null as Jack suggested above, the script produced by the code will be identical to the option 2 and will result to the same error. 然后,如果上面提到的param2 = null,那么代码生成的脚本将与选项2相同,并将导致相同的错误。 So you cannot use NULL in this case.You cannot set DEFAULT as the value of SQLParameter either. 所以你不能在这种情况下使用NULL 。你也不能将DEFAULT设置为SQLParameter的值。

What you can do is to create a stored procedure to wrap the call to your funcion and move your default value from the function to the SP. 你可以做的是创建一个存储过程来包装对你的函数的调用,并将你的默认值从函数移动到SP。 Example: 例:

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

The .NET code will look the following way: .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())
            {
                //...
            }
        }
    }
}

In this case null as a value for the param2 will be translated to the correct DEFAULT and the following script will be produced: 在这种情况下,作为param2的值的null将被转换为正确的DEFAULT,并将生成以下脚本:

exec USP_SAMPLE_PROCEDURE @Param1=N'ABC',@Param2=default,@Statement=N'SELECT * FROM dbo.UFN_SAMPLE_FUNCTION (@P1, @P2)'

which will give you the following result: 这会给你以下结果:

Col1       Col2
---------- -----------
ABC        NULL

I am not sure that this is the best practice. 我不确定这是最好的做法。 This is just the work-around. 这只是解决方法。

Though you can't set an SQL keyword as the value of a parameter, you could in this case go and get the DEFAULT VALUE. 虽然您不能将SQL关键字设置为参数的值,但在这种情况下,您可以获取DEFAULT VALUE。

 SELECT COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS 
      WHERE TABLE_NAME = 'table_name' AND COLUMN_NAME = 'column_name'"

如果你传递一个dot net null值作为参数值,它将使用sql DEFAULT如果你传递一个点网DBNull.Value它将使用sql NULL

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM