Как проверить, существует ли хранимая процедура перед ее созданием - PullRequest
250 голосов
/ 15 января 2010

У меня есть сценарий SQL, который должен запускаться каждый раз, когда клиент выполняет функцию «управления базой данных». Сценарий включает в себя создание хранимых процедур в клиентской базе данных. Некоторые из этих клиентов могут уже иметь хранимую процедуру при запуске сценария, а некоторые - нет. Мне нужно добавить отсутствующие хранимые процедуры в клиентскую базу данных, но не имеет значения, сколько я пытаюсь изменить синтаксис T-SQL, я получаю

CREATE / ALTER PROCEDURE 'должно быть первым оператором в пакете запроса

Я читал это удаление перед созданием работ, но мне не нравится делать это таким образом.

IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'MyProc')
DROP PROCEDURE MyProc
GO

CREATE PROCEDURE MyProc
...

Как добавить проверку на наличие хранимой процедуры и создать ее, если она не существует, но изменить ее, если она существует?

Ответы [ 18 ]

432 голосов
/ 22 мая 2010

Я понимаю, что это уже было помечено как ответ, но мы привыкли делать это так:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND OBJECT_ID = OBJECT_ID('dbo.MyProc'))
   exec('CREATE PROCEDURE [dbo].[MyProc] AS BEGIN SET NOCOUNT ON; END')
GO

ALTER PROCEDURE [dbo].[MyProc] 
AS
  ....

Просто чтобы не отбросить процедуру.

169 голосов
/ 15 января 2010

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

Просто скопируйте все после AS:

BEGIN
    DECLARE @myvar INT
    SELECT  *
    FROM    mytable
    WHERE   @myvar ...
END

Этот код выполняет те же действия, что и хранимый процесс, но не хранится на стороне базы данных.

Это очень похоже на анонимную процедуру в PL/SQL.

Обновление:

Название вашего вопроса немного сбивает с толку.

Если вам нужно только создать процедуру, если она не существует, тогда ваш код в порядке.

Вот что SSMS выводит в скрипте создания:

IF EXISTS ( SELECT  *
            FROM    sys.objects
            WHERE   object_id = OBJECT_ID(N'myproc')
                    AND type IN ( N'P', N'PC' ) ) 
DROP …
CREATE …

Обновление:

Пример того, как это сделать при включении схемы:

IF EXISTS ( SELECT * 
            FROM   sysobjects 
            WHERE  id = object_id(N'[dbo].[MyProc]') 
                   and OBJECTPROPERTY(id, N'IsProcedure') = 1 )
BEGIN
    DROP PROCEDURE [dbo].[MyProc]
END

В приведенном выше примере dbo - это схема.

Обновление:

В SQL Server 2016+ вы можете просто сделать

CREATE OR ALTER PROCEDURE dbo.MyProc

112 голосов
/ 16 ноября 2011

Если вы ищете самый простой способ проверить существование объекта базы данных перед его удалением, вот один из способов (в примере используется SPROC, как и в предыдущем примере, но его можно изменить для таблиц, индексов и т. Д.) ):

IF (OBJECT_ID('MyProcedure') IS NOT NULL)
  DROP PROCEDURE MyProcedure
GO

Это быстро и элегантно, но вам нужно убедиться, что у вас есть уникальные имена объектов для всех типов объектов, так как это не учитывает это.

Надеюсь, это поможет!

28 голосов
/ 28 марта 2017

Я знаю, что вы хотите "изменить процедуру, если она существует, и удалить ее, только если она не существует", но я считаю, что проще просто всегда отбросить процедуру, а затем заново создать ее. Вот как можно удалить процедуру, только если она уже существует:

IF OBJECT_ID('MyProcedure', 'P') IS NOT NULL
    DROP PROCEDURE MyProcedure
GO

Второй параметр указывает OBJECT_ID искать только объекты с object_type = 'P', , которые являются хранимыми процедурами:

AF = Агрегатная функция (CLR)

C = ПРОВЕРЬТЕ ограничение

D = ПО УМОЛЧАНИЮ (ограничение или автономно)

F = ограничение FOREIGN KEY

FN = скалярная функция SQL

FS = Сборочная (CLR) скалярная функция

FT = табличная функция сборки (CLR)

IF = встроенная табличная функция SQL

IT = Внутренний стол

P = хранимая процедура SQL

ПК = хранимая процедура сборки (CLR)

PG = План руководства

PK = ограничение ПЕРВИЧНОГО КЛЮЧА

R = Правило (в старом стиле, автономное)

RF = Процедура фильтра репликации

S = Базовая системная таблица

SN = Синоним

SO = объект последовательности

TF = табличная функция SQL

Вы можете получить полный список опций:

SELECT name 
FROM master..spt_values
WHERE type = 'O9T'
20 голосов
/ 09 ноября 2016

Начиная с SQL SERVER 2016, вы можете использовать новый DROP PROCEDURE IF EXISTS.
DROP { PROC | PROCEDURE } [ IF EXISTS ] { [ schema_name. ] procedure } [ ,...n ]

Ссылка: https://msdn.microsoft.com/en-us/library/ms174969.aspx

17 голосов
/ 23 ноября 2016

Я знаю, что это очень старая запись, но, поскольку она появляется в верхних результатах поиска, следовательно, добавляется последнее обновление для тех, кто использует SQL Server 2016 SP1 -

create or alter procedure procTest
as
begin
 print (1)
end;
go

Создает хранимую процедуру, если она еще не существует, но изменяет ее, если существует.

Ссылка

7 голосов
/ 16 августа 2012

У меня была такая же ошибка. Я знаю, что этот поток уже практически мертв, но я хочу установить другую опцию, кроме "анонимной процедуры".

Я решил это так:

  1. Проверьте, существует ли хранимая процедура:

    IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='my_procedure') BEGIN
        print 'exists'  -- or watever you want
    END ELSE BEGIN
        print 'doesn''texists'   -- or watever you want
    END
    
  2. Однако "CREATE/ALTER PROCEDURE' must be the first statement in a query batch" все еще там. Я решил это так:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE -- view procedure function or anything you want ...
    
  3. Я получаю этот код:

    IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID('my_procedure'))
    BEGIN
        DROP PROCEDURE my_procedure
    END
    
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE PROCEDURE [dbo].my_procedure ...
    
5 голосов
/ 21 марта 2014

Вот метод и некоторые аргументы за его использование. Редактировать сохраненный процесс не так приятно, но есть плюсы и минусы ...

ОБНОВЛЕНИЕ: Вы можете также обернуть весь этот вызов в СДЕЛКУ. Включая множество хранимых процедур в одну транзакцию, которая может зафиксировать или откатить все. Еще одним преимуществом переноса транзакции является то, что хранимая процедура всегда существует для других соединений SQL, если они не используют уровень изоляции транзакции READ UNCOMMITTED!

1) Избегать изменений просто как решение процесса. Наши процессы должны всегда, ЕСЛИ СУЩЕСТВУЕТ, ТО, ЧЕМ СОЗДАТЬ. Если вы сделаете то же самое, предполагая, что новый PROC является желаемым процессом, обслуживание изменений будет немного сложнее, потому что у вас будет IF EXISTS ALTER ELSE CREATE.

2) Вы должны поместить CREATE / ALTER в качестве первого вызова в пакете, чтобы нельзя было обернуть последовательность обновлений процедур в транзакции вне динамического SQL. В основном, если вы хотите запустить целый стек обновлений процедур или откатить их все назад, не восстанавливая резервную копию БД, это способ сделать все в одном пакете.

IF NOT EXISTS (select ss.name as SchemaName, sp.name as StoredProc 
    from sys.procedures sp
    join sys.schemas ss on sp.schema_id = ss.schema_id
    where ss.name = 'dbo' and sp.name = 'MyStoredProc')
BEGIN
    DECLARE @sql NVARCHAR(MAX)

    -- Not so aesthetically pleasing part. The actual proc definition is stored
    -- in our variable and then executed.
    SELECT @sql = 'CREATE PROCEDURE [dbo].[MyStoredProc]
(
@MyParam int
)
AS
SELECT @MyParam'
    EXEC sp_executesql @sql
END
4 голосов
/ 21 марта 2016

В Sql server 2008 и далее вы можете использовать "INFORMATION_SCHEMA.ROUTINES"

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES 
  WHERE ROUTINE_NAME = 'MySP'
        AND ROUTINE_TYPE = 'PROCEDURE') 
3 голосов
/ 04 марта 2015

** Самый простой способ удалить и восстановить сохраненный процесс в T-Sql - **

Use DatabaseName
go
If Object_Id('schema.storedprocname') is not null
begin
   drop procedure schema.storedprocname
end
go

create procedure schema.storedprocname
as

begin
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...