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

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

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

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

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

CREATE PROCEDURE MyProc
...

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

Ответ 1

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

Просто скопируйте все после 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

Ответ 2

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

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
  ....

Чтобы избежать процедуры, выполните следующие действия.

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

C = CHECK ограничение

D = DEFAULT (ограничение или автономно)

F = ограничение КЛЮЧЕВОЙ КЛЮЧ

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

Скалярная функция FS = Assembly (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'

Ответ 6

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

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

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

Ссылка

Ответ 7

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

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

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

    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
    
  • Однако "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 ...
    
  • Я получаю код:

    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 ...
    

Ответ 8

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

UPDATE: вы можете также обернуть весь этот вызов в транзакции. Включение многих хранимых процедур в одну транзакцию, которая может все совершить или все откат. Еще одно преимущество переноса транзакции - хранимая процедура всегда существует для других соединений 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

Ответ 9

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

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES 
  WHERE ROUTINE_NAME = 'MySP'
        AND ROUTINE_TYPE = 'PROCEDURE') 

Ответ 10

У меня, видимо, нет репутации, необходимой для голосования или комментариев, но я просто хотел сказать, что ответ Джеффа с использованием EXEC (sp_executesql может быть лучше), безусловно, путь. Отбрасывание, а затем повторное создание хранимой процедуры завершается в конце, но есть момент, когда хранимая процедура вообще не существует, и это может быть очень плохо, особенно если это то, что будет многократно повторяйте. У меня возникли проблемы со своим приложением, потому что фоновый поток выполнял IF EXISTS DROP... CREATE, в то время как другой поток пытался использовать хранимую процедуру.

Ответ 11

** Самый простой способ сбросить и воссоздать хранимую процедуру в 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

Ответ 12

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

IF NOT EXISTS (
    SELECT *
    FROM sys.objects
    WHERE object_id = OBJECT_ID(N'[dbo].[uspMyProcedure]')
    )
BEGIN
  EXEC sp_executesql N'CREATE PROCEDURE [dbo].[uspMyProcedure] AS select 1'
END
GO

ALTER PROCEDURE [dbo].[uspMyProcedure] 
    @variable1 INTEGER  
AS
BEGIN
   -- Stored procedure logic
END

Ответ 13

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

IF EXISTS (SELECT * FROM sys.objects 
            WHERE object_id = OBJECT_ID
             (N'[Schema].[Procedure_Name]') AND type IN (N'P', N'PC'))
BEGIN
       DROP PROCEDURE [Schema].[Procedure_Name]
       Print('Proceudre dropped => [Schema].[Procedure_Name]')
END

Проверьте IF Exist for Trigger, Function, также нажав ссылку http://www.gurujipoint.com/2017/05/check-if-exist-for-trigger-function-and.html

Ответ 15

почему бы вам не пойти простым способом, как

    IF EXISTS(SELECT * FROM sys.procedures WHERE NAME LIKE 'uspBlackListGetAll')
    BEGIN
         DROP PROCEDURE uspBlackListGetAll
    END
    GO

    CREATE Procedure uspBlackListGetAll

..........

Ответ 16

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

Ответ 17

Если вам нужно изменить хранимую процедуру перед каждым запуском, возможно, вы можете сохранить ее текст как простой текст в столбце varchar (max) и выполнить его с помощью sp_executesql.

Хотя я не могу понять, почему ALTER PROCEDURE будет хуже этого.

Ответ 18

В дополнение к ответу @Geoff я создал простой инструмент, который генерирует SQL файл, который содержит инструкции для хранимых процедур, представлений, функций и триггеров.

См. MyDbUtils @CodePlex. введите описание изображения здесь

Ответ 19

Интересно! Почему я не пишу весь запрос, например

GO
create procedure [dbo].[spAddNewClass] @ClassName varchar(20),@ClassFee int
as
begin
insert into tblClass values (@ClassName,@ClassFee)
end

GO
create procedure [dbo].[spAddNewSection] @SectionName varchar(20),@ClassID       int
as
begin
insert into tblSection values(@SectionName,@ClassID)
end

Go
create procedure test
as
begin 
select * from tblstudent
end

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

Ответ 20

СОЗДАТЬ процедуру, ЕСЛИ НЕ СУЩЕСТВУЕТ "Ваше прок-имя" () BEGIN... END