Pregunta

Tengo una consulta SQL parametrizada que se realiza para SQL2005 que se crea dinámicamente en el código, por lo que utilicé el ADO.NET SqlParameter clase para agregar parámetros SQL a SqlCommand.

En el SQL mencionado anteriormente, selecciono entre una función valorada de tabla con valores predeterminados. Quiero que mi SQL dinámico a veces especifique un valor para estos parámetros predeterminados, y otras veces quiero especificar que el SQL DEFAULT - como se define en la función valorada de la tabla - debe usarse.

Para mantener el código limpio No quería agregar dinámicamente el SQL DEFAULT Palabra clave y parámetro cuando se utilizará un no defecto, solo quería establecer DEFAULT Como el valor de mi SQLParameter.

¿Yo puedo? ¿Cuál es la mejor práctica en tal caso?

¿Fue útil?

Solución

Los parámetros de consulta SQL toman el lugar de los valores literal solamente.

No puede enviar una palabra clave SQL como el valor de un parámetro, al igual que no puede enviar un identificador de tabla, identificador de columna, lista de valores (por ejemplo, para un IN predicado), o una expresión. El valor del parámetro es siempre interpretado como un valor literal, como si hubiera incluido una cadena citada literal o un literal numérico en su consulta.

Lo siento, pero debe incluir una palabra clave SQL como parte de la consulta SQL antes de Preparas esa consulta.

Otros consejos

AFAIK, la única forma de decirle a SQL Server que use un valor predeterminado es a través del DEFAULT palabra clave o para excluirla de la lista de parámetros. Eso significa que el uso del DEFAULT La palabra clave debe estar en su instrucción SQL parametrizada. Entonces, algo como:

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

Supongo que otro enfoque sería consultar los catálogos del sistema para el valor real de los diversos DEFAULT Valores y determine si establecer el SQLParameter en el valor predeterminado de esa manera, pero eso requiere una segunda consulta enrevesada para obtener los valores predeterminados.

Si tiene la siguiente función (por ejemplo):

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

Entonces puede usarlo de la siguiente manera (Opción 1):

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

Lo cual es una forma correcta y obtienes el siguiente resultado:

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

Pero si intenta usar la consulta parametrizada (opción 2):

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

recibirá un 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.

Si tiene el siguiente código .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())
            {
                //...
            }
        }
    }
}

Luego, en el caso de param2 = null como Jack sugerido anteriormente, el script producido por el código será idéntico a la opción 2 y dará como resultado el mismo error. Entonces no puedes usar NULO En este caso, no puedes establecer DEFECTO como el valor del parámetro SQLPARE.

Lo que puede hacer es crear un procedimiento almacenado para envolver la llamada a su función y mover su valor predeterminado de la función al SP. Ejemplo:

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

El código .NET se verá de la siguiente manera:

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())
            {
                //...
            }
        }
    }
}

En este caso nulo como un valor para el param2 será traducido al correcto DEFECTO y se producirá el siguiente guión:

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

que le dará el siguiente resultado:

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

No estoy seguro de que esta sea la mejor práctica. Esto es solo la solución al trabajo.

Aunque no puede establecer una palabra clave SQL como el valor de un parámetro, en este caso podría ir y obtener el valor predeterminado.

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

Si pasa un valor nulo neto de puntos como el valor del parámetro, utilizará el valor predeterminado de SQL si pasa un DOT net dbnull.value usará SQL NULL

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top