Как проверить, существует ли функция в базе данных SQL

138

Мне нужно выяснить, существует ли функция в базе данных, чтобы я мог ее удалить и создать заново. Это должно быть что-то вроде следующего кода, который я использую для хранимых процедур:

IF EXISTS (
     SELECT  *
     FROM    dbo.sysobjects
     WHERE   id = OBJECT_ID(N'[dbo].[SP_TEST]')
             AND OBJECTPROPERTY(id, N'IsProcedure') = 1 )
Доктор Гринтхумб
источник

Ответы:

206

Это то, что использует SSMS, когда вы пишете сценарий, используя DROP and CREATEопцию

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 

Этот подход к развертыванию изменений означает, что вам необходимо заново создать все разрешения для объекта, чтобы вы могли рассмотреть ALTER-ing, если вместо этого существует.

Мартин Смит
источник
17
Еще больше удивляет, почему нет представления системного каталога sys.functions .....
marc_s
61

Я склонен использовать Information_Schema:

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

для функций и изменения Routine_Typeдля хранимых процедур

IF EXISTS ( SELECT  1
            FROM    Information_schema.Routines
            WHERE   Specific_schema = 'dbo'
                    AND specific_name = 'Foo'
                    AND Routine_Type = 'PROCEDURE' ) 
Закон Мецлер
источник
2
Круто я искал что то подобное и так и не нашел. Я считаю, что лучше использовать information_schema в целом, поскольку он не привязан к конкретной СУБД. (кстати, идея о кросс-платформенной совместимости возникла из этого ответа: stackoverflow.com/a/14290099/420667 )
user420667
40

Почему бы просто:

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

Второй аргумент object_idнеобязателен, но может помочь определить правильный объект. Существует множество возможных значений для этого аргумента типа, в частности:

  • FN: скалярная функция
  • IF: встроенная табличная функция
  • TF: табличная функция
  • Скалярная функция FS: Assembly (CLR)
  • FT: Сборочная (CLR) табличная функция
Kape
источник
4
Технически это может потерпеть неудачу, поскольку он только проверяет, есть ли объект с таким именем. Не то, что есть объект, а что это функция. Например, если CREATE TABLE YourFunctionName(X INT);запустить код не удастся.
Мартин Смит
1
@MartinSmith: легко сделать надежным. Просто используйте object_id('YourFunction', 'FN')или любой другой указатель (второй аргумент), который проясняет, на какой объект вы ссылаетесь.
Дарлов
@darlove с использованием 'FN' в качестве второго параметра может не работать. Я только что узнал. «FN» означает скалярную функцию. Эта ссылка сообщает вам различные значения параметров, которые вы можете передать sqlhints.com/tag/how-to-check-if-function-exists . Я продолжаю использовать 'FN', чтобы проверить существующую функцию значения таблицы, и она не работает. Я должен использовать «TF»
user12345
9

Я обнаружил, что вы можете использовать очень не многословный и простой подход к проверке существования различных объектов SQL Server следующим образом:

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

Это основано на функции OBJECTPROPERTY, которая доступна в SQL 2005+. Статью MSDN можно найти здесь .

Функция OBJECTPROPERTY использует следующую подпись:

OBJECTPROPERTY ( id , property ) 

Вы передаете литеральное значение в параметр свойства, обозначая тип объекта, который вы ищете. Существует огромный список ценностей, которые вы можете предоставить.

Джереми
источник
Я думаю, что было бы легче увидеть простоту этого ответа, если бы он включал полный пример if / drop.
Джонатан
6

Я знаю, что эта ветка старая, но я просто хотел добавить этот ответ тем, кто считает, что безопаснее, Alterчем Dropи Create. Ниже будет , если она существует , или он , если не делает:AlterFunctionCreate

  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
источник
2
Мне это нравится, но я думаю, что это должно быть "ALTER FUNCTION", нет?
Эрик
Мне нравитсяALTER OR CREATE
AgentFire