Como verificar se existe uma função em um banco de dados SQL

138

Preciso descobrir se existe uma função em um banco de dados, para que eu possa descartá-la e criá-la novamente. Basicamente, deve ser algo como o seguinte código que eu uso para procedimentos armazenados:

IF EXISTS (
     SELECT  *
     FROM    dbo.sysobjects
     WHERE   id = OBJECT_ID(N'[dbo].[SP_TEST]')
             AND OBJECTPROPERTY(id, N'IsProcedure') = 1 )
Dr. Greenthumb
fonte

Respostas:

206

É isso que o SSMS usa quando você script usando a DROP and CREATEopção

IF EXISTS (SELECT *
           FROM   sys.objects
           WHERE  object_id = OBJECT_ID(N'[dbo].[foo]')
                  AND type IN ( N'FN', N'IF', N'TF', N'FS', N'FT' ))
  DROP FUNCTION [dbo].[foo]

GO 

Essa abordagem para implantar alterações significa que você precisa recriar todas as permissões no objeto para poder considerar a opção ALTERse existir.

Martin Smith
fonte
17
Faz-me pensar ainda mais porque não há uma sys.functions vista catálogo do sistema .....
marc_s
61

Costumo usar o Information_Schema:

IF EXISTS ( SELECT  1
            FROM    Information_schema.Routines
            WHERE   Specific_schema = 'dbo'
                    AND specific_name = 'Foo'
                    AND Routine_Type = 'FUNCTION' ) 

para funções e alteração Routine_Typepara procedimentos armazenados

IF EXISTS ( SELECT  1
            FROM    Information_schema.Routines
            WHERE   Specific_schema = 'dbo'
                    AND specific_name = 'Foo'
                    AND Routine_Type = 'PROCEDURE' ) 
Law Metzler
fonte
2
Legal, eu estava procurando por algo assim e nunca o encontrei. Eu acredito que é melhor usar o information_schema em geral, pois não está vinculado a um RDBMS específico. (btw a noção de ser multi-plataforma compatível veio esta resposta: stackoverflow.com/a/14290099/420667 )
user420667
40

Por que não apenas:

IF object_id('YourFunctionName', 'FN') IS NOT NULL
BEGIN
    DROP FUNCTION [dbo].[YourFunctionName]
END
GO

O segundo argumento de object_idé opcional, mas pode ajudar a identificar o objeto correto. Existem vários valores possíveis para esse argumento de tipo, particularmente:

  • FN: Função escalar
  • IF: função com valor de tabela embutido
  • TF: Função com valor de tabela
  • FS: Função escalar Assembly (CLR)
  • FT: Função com valor de tabela Assembly (CLR)
Kapé
fonte
4
Tecnicamente, isso pode falhar, pois apenas verifica se existe um objeto com esse nome. Não que exista um objeto e que seja uma função. EG Se estiver CREATE TABLE YourFunctionName(X INT);executando o código falhará.
Martin Smith
1
@ MartinSmith: Fácil de fazer robusto. Basta usar object_id('YourFunction', 'FN')ou qualquer outro designador (segundo argumento) que deixe claro a que tipo de objeto você está se referindo.
precisa saber é
@darlove usando 'FN' como segundo parâmetro pode não funcionar. Eu acabei de aprender 'FN' significa função escalar. Este link informa diferentes valores de parâmetros que você pode passar para sqlhints.com/tag/how-to-check-if-function-exists . Eu continuo usando 'FN' para verificar a função de valor de tabela existente e ela não funciona. Eu tenho que usar 'TF'
user12345
9

Eu descobri que você pode usar uma abordagem muito não detalhada e direta para verificar a existência de vários objetos do SQL Server desta maneira:

IF OBJECTPROPERTY (object_id('schemaname.scalarfuncname'), 'IsScalarFunction') = 1
IF OBJECTPROPERTY (object_id('schemaname.tablefuncname'), 'IsTableFunction') = 1
IF OBJECTPROPERTY (object_id('schemaname.procname'), 'IsProcedure') = 1

Isso se baseia na função OBJECTPROPERTY, disponível no SQL 2005+. O artigo do MSDN pode ser encontrado aqui .

A função OBJECTPROPERTY usa a seguinte assinatura:

OBJECTPROPERTY ( id , property ) 

Você passa um valor literal para o parâmetro de propriedade, designando o tipo de objeto que está procurando. Há uma lista enorme de valores que você pode fornecer.

Jeremy
fonte
Eu acho que seria mais fácil ver a simplicidade dessa resposta se ela incluísse um exemplo completo se / soltar.
Jonathan
6

Eu sei que este tópico é antigo, mas eu só queria adicionar esta resposta para aqueles que acreditam que é mais seguro do Alterque Drope Create. A seguir, Altero Functionse existe ou Createse não existe:

  IF NOT EXISTS (SELECT *
               FROM   sys.objects
               WHERE  object_id = OBJECT_ID(N'[dbo].[foo]')
                      AND type IN ( N'FN', N'IF', N'TF', N'FS', N'FT' ))
       EXEC('CREATE FUNCTION [dbo].[foo]() RETURNS INT AS BEGIN RETURN 0 END')
  GO
  ALTER FUNCTION [dbo].[foo]
  AS
  ...
jamiedanq
fonte
2
Eu gosto disso, mas acho que deveria ser "ALTER FUNCTION", não?
Erik
Eu gostoALTER OR CREATE
AgentFire 30/03