T-SQL: función con parámetros predeterminados

155

Tengo este script:

CREATE FUNCTION dbo.CheckIfSFExists(@param1 INT, @param2 BIT = 1 )
RETURNS BIT
AS
BEGIN
    IF EXISTS ( bla bla bla )
        RETURN 1;
    RETURN 0;
END
GO

Quiero usarlo en un procedimiento de esta manera:

IF dbo.CheckIfSFExists( 23 ) = 0
    SET @retValue = 'bla bla bla';

Pero me sale el error:

Se proporcionó un número insuficiente de argumentos para el procedimiento o la función dbo.CheckIfSFExists.

Por que no funciona?

nirmus
fuente

Respuestas:

227

tienes que llamarlo así

SELECT dbo.CheckIfSFExists(23, default)

De Technet :

Cuando un parámetro de la función tiene un valor predeterminado, la palabra clave DEFAULT debe especificarse cuando se llama a la función para recuperar el valor predeterminado. Este comportamiento es diferente del uso de parámetros con valores predeterminados en procedimientos almacenados en los que omitir el parámetro también implica el valor predeterminado. Una excepción a este comportamiento es cuando se invoca una función escalar utilizando la instrucción EXECUTE. Cuando se utiliza EXECUTE, no se requiere la palabra clave DEFAULT.

SQLMenace
fuente
80
Al ver esto estoy frustrado. No estoy aprovechando el defaultconcepto aquí ... Necesito ir y cambiar todos los lugares ahora.
LCJ
8
@Lijo, aún tiene la ventaja de no duplicar su valor predeterminado concreto en cada llamada.
Frédéric
9
Como no se nos permite superponer, y el "valor predeterminado" por lo tanto tiene una usabilidad limitada, a menudo el mejor enfoque será crear una nueva versión extendida con un sufijo (digamos CheckIfSFExistsEX aquí) con los parámetros adicionales y cambiar la función original a solo llamando a la versión extendida con el parámetro "predeterminado". De esta manera, TODO el código existente funciona y solo tiene un lugar para mantener.
Eske Rahn
39

Puede llamarlo de tres maneras: con parámetros, con PREDETERMINADO y mediante EJECUTAR

SET NOCOUNT ON;

DECLARE
@Table  SYSNAME = 'YourTable',
@Schema SYSNAME = 'dbo',
@Rows   INT;

SELECT dbo.TableRowCount( @Table, @Schema )

SELECT dbo.TableRowCount( @Table, DEFAULT )

EXECUTE @Rows = dbo.TableRowCount @Table

SELECT @Rows
Douglas Osborne
fuente
11
¿Por qué DEFAULTse requiere la palabra clave en select, pero se puede omitir en execute? Esto apesta: / Espero que esto se arregle algún día.
Misiu
@Misiu, no es algo que deba "arreglarse". Eso es por diseño. Leí muchas alternativas para abordar un objetivo "ideal" de simplemente poder llamar a una función sin especificar cada argumento, pero no vi una explicación clara de por qué eso es necesario. El código debe ser claro y una estrategia para lograr eso requiere que el codificador siempre sea consciente de que "oye, estás llamando a una función que TIENE este y estos otros argumentos, que tienen valores predeterminados. No olvides que los valores predeterminados PUEDEN CAMBIARSE ". Entonces, en mi opinión, es una buena "mala cosa" tener.
Gustavo Pinsard
16

Con las funciones definidas por el usuario, debe declarar cada parámetro, incluso si tienen un valor predeterminado.

Lo siguiente se ejecutaría con éxito:

IF dbo.CheckIfSFExists( 23, default ) = 0
    SET @retValue = 'bla bla bla;
Brusco
fuente
-1

Una forma de evitar este problema es utilizar procedimientos almacenados con un parámetro de salida.

exec sp_mysprocname @returnvalue output, @firstparam = 1, @ secondparam = 2

valores que no pasa por defecto a los valores predeterminados establecidos en el procedimiento almacenado. Y puede obtener los resultados de su variable de salida.

Jereme Guenther
fuente
1
En general, cambiar su función a un procedimiento almacenado no es una buena solución, porque no se puede llamar a un procedimiento almacenado desde una consulta, pero sí una función.
Blade
Es cierto, sin embargo, no todos los bloques de código deben llamarse desde una consulta. Se ha demostrado que sql no tiene un buen método para manejar valores predeterminados para funciones (usar la palabra clave predeterminada es casi tanto trabajo como agregar un valor). No es una buena solución general, pero funciona muy bien en ciertos casos de uso.
Jereme Guenther
La gente sigue marcando esto, pero me quedo con eso. Si tiene la necesidad de tener un fragmento de código reutilizable, que no se invocará dentro de las consultas, y desea la flexibilidad de los parámetros opcionales verdaderos con valores predeterminados, un procedimiento almacenado es aún mejor que una función.
Jereme Guenther
1
Usar procedimientos almacenados no significa usarlos en lugar de usar una función; puede significar usar el procedimiento almacenado como una envoltura alrededor de una función. Yo uso esta técnica a menudo; las palabras clave predeterminadas ahora están ocultas dentro del proceso. Creo que esta idea está bien. También me permite establecer valores predeterminados más complicados si lo deseo, separados de la función, que se puede dejar en un estado más puro.
J Bryan Precio