T-SQL - função com parâmetros padrão

155

Eu tenho 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

Eu quero usá-lo em um procedimento desta maneira:

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

Mas eu recebo o erro:

Um número insuficiente de argumentos foi fornecido para o procedimento ou função dbo.CheckIfSFExists.

Por que isso não funciona?

nirmus
fonte

Respostas:

227

você tem que chamar assim

SELECT dbo.CheckIfSFExists(23, default)

De Technet :

Quando um parâmetro da função possui um valor padrão, a palavra-chave DEFAULT deve ser especificada quando a função é chamada para recuperar o valor padrão. Esse comportamento é diferente de usar parâmetros com valores padrão em procedimentos armazenados nos quais a omissão do parâmetro também implica o valor padrão. Uma exceção a esse comportamento é ao chamar uma função escalar usando a instrução EXECUTE. Ao usar EXECUTE, a palavra-chave DEFAULT não é necessária.

SQLMenace
fonte
80
Vendo isso, estou frustrado. Não estou aproveitando o defaultconceito aqui ... preciso mudar todos os lugares agora.
LCJ 12/09
8
@Lijo, você ainda tem a vantagem de não duplicar seu valor padrão concreto a cada chamada.
Frédéric
9
Como não temos permissão para sobrepor, e o "padrão", portanto, possui usabilidade limitada, geralmente a melhor abordagem será criar uma nova versão estendida com um sufixo (por exemplo, CheckIfSFExistsEX aqui) com os parâmetros extras e alterar a função original para apenas chamando a versão estendida com o parâmetro "padrão". Dessa forma, TODO o código existente funciona e você só tem um lugar para manter.
precisa
39

Você pode chamá-lo de três maneiras - com parâmetros, com DEFAULT e via EXECUTE

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
fonte
11
Por que a DEFAULTpalavra-chave é necessária em select, mas pode ser omitida em execute? Isso é péssimo: / Espero que isso seja corrigido algum dia.
Misiu 9/01/19
@Misiu, não é algo que precise ser "consertado". Isso é por design. Li muitas alternativas para abordar um objetivo "ideal" de simplesmente poder chamar uma função sem especificar todos os argumentos, mas não vi uma explicação clara do motivo pelo qual isso é necessário. O código deve ser claro e uma estratégia para alcançar isso é exigir que o codificador esteja sempre ciente de que "ei, você está chamando uma função que possui esse e outros argumentos, que possuem valores padrão. Não esqueça que o valores padrão PODEM SER ALTERADOS ". Então, IMO, isso é uma "coisa ruim" boa de se ter.
Gustavo Pinsard 17/07
16

Com funções definidas pelo usuário, você deve declarar todos os parâmetros, mesmo que eles tenham um valor padrão.

O seguinte seria executado com sucesso:

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

Uma maneira de contornar esse problema é usar procedimentos armazenados com um parâmetro de saída.

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

valores que você não passa no padrão para os padrões definidos no próprio procedimento armazenado. E você pode obter os resultados da sua variável de saída.

Jereme Guenther
fonte
1
Alterar sua função para um procedimento armazenado geralmente não é uma boa solução, porque um procedimento armazenado não pode ser chamado de dentro de uma consulta, mas uma função pode.
Blade
É verdade que nem todos os blocos de código precisam ser chamados de dentro de uma consulta. Foi demonstrado que o sql não tem um bom método de manipular valores padrão para funções (usar a palavra-chave padrão é quase tão trabalho quanto adicionar um valor). Não é uma boa solução geral, mas funciona muito bem em certos casos de uso.
precisa
As pessoas continuam anotando isso, no entanto, eu estou mantendo isso. Se você precisar de um pedaço de código reutilizável, que não será chamado dentro de consultas, e desejar a flexibilidade de parâmetros opcionais verdadeiros com valores padrão, um procedimento armazenado ainda é melhor que uma função.
Jereme Guenther
1
Usar procedimentos armazenados não significa usá-los em vez de usar uma função - pode significar usar o procedimento armazenado como um invólucro em torno de uma função. Eu uso essa técnica frequentemente; as palavras-chave padrão agora estão ocultas dentro do proc. Eu acho que essa ideia está bem. Ele também me permite fazer padrões mais complicados, se eu quiser - separados da função, que pode ser deixada em um estado mais puro.
J Bryan Preço