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


130

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

Как я могу это сделать в sql.

Я использую SQL Server 2005


Ответы:


160

Если вы УДАЛИТЕ и СОЗДАЕТЕ процедуру, вы потеряете настройки безопасности. Это может раздражать администратора базы данных или вообще нарушить работу вашего приложения.

Что я делаю, так это создаю тривиальную хранимую процедуру, если она еще не существует. После этого вы можете ИЗМЕНИТЬ хранимую процедуру по своему усмотрению.

IF object_id('YourSp') IS NULL
    EXEC ('create procedure dbo.YourSp as select 1')
GO
ALTER PROCEDURE dbo.YourSp
AS
...

Таким образом, настройки безопасности, комментарии и другие метаданные сохранятся после развертывания.


2
По крайней мере, если вы его отбросите, вы знаете, что вам нужно повторно добавить разрешения. Если вы запустите этот sql, вы не узнаете, имеет ли sproc правильные разрешения или нет, поскольку вы не узнаете, создали ли вы его или изменили его.
Liazy

@Liazy простое решение - добавить код if object_id('YourSp') is null BEGIN ... ENDдля добавления соответствующих разрешений после создания хранимой процедуры.
saluce

4
думаю, что другой ответ немного более полный, поскольку он извлекает только идентификатор объекта для хранимых процедур. не принято иметь одно и то же имя для разных типов, но такое могло случиться
workabyte

149

Самый чистый способ - проверить его существование, отбросить, если он существует, а затем воссоздать его. Вы не можете встроить оператор create proc в оператор IF. Это должно хорошо работать:

IF OBJECT_ID('MySproc', 'P') IS NOT NULL
DROP PROC MySproc
GO

CREATE PROC MySproc
AS
BEGIN
    ...
END

1
Это будет работать, но удалит все изменения безопасности, примененные к хранимой процедуре.
Andomar 02

18
Изменения безопасности также должны быть частью скриптов. Таким образом, это будет должным образом задокументировано. Это правильный подход.
Эндер Виггин

@EnderWiggin За исключением случаев, когда реализация безопасности неизвестна во время разработки ... Что делать, если разработчик не знает, каким пользователям нужны права на выполнение?
Adriaan Davel

2
@AdriaanDavel Для этого нужны администраторы баз данных, и заставить администраторов баз данных поговорить с разработчиками называется управлением. Если разработчики и администраторы баз данных не могут работать вместе, возникает проблема с компанией. Кроме того, правильно реализованные системы не полагаются на права пользователя прикасаться к базе данных, для чего предназначены учетные записи служб, а безопасность уровня обслуживания должна применяться ко всей базе данных, таким образом администраторы баз данных не должны тратить время и деньги на настройку безопасности на отдельные звездочки.
Шон Уилсон

2
У меня не было бы разработчиков, отбрасывающих / воссоздающих sprocs, принадлежащие коммерческому продукту. Если подумать, я бы тоже не велел администраторам баз данных делать это. Тем не менее, я понимаю, к чему вы клоните, а именно: «что, если администраторам баз данных потребуется настроить безопасность после развертывания sproc для коммерческого продукта». Я повторю, что правильно реализованные системы не полагаются на права пользователя и что безопасность на уровне обслуживания должна применяться ко всей базе данных. Я работал с администраторами баз данных, которые устанавливаются в демонстрационную / рабочую систему, а затем сравнивают схемы, чтобы гарантировать безопасность обновления, ИМО, это то, для чего они наняты.
Шон Уилсон

31

Если вы имеете дело только с хранимыми процедурами, проще всего, вероятно, отказаться от процедуры, а затем воссоздать ее. Вы можете сгенерировать весь код для этого с помощью мастера создания сценариев в SQL Server.

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[YourSproc]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[YourSproc]

CREATE PROCEDURE YourSproc...

20

Из SQL Server 2016 CTP3вы можете использовать новые операторы DIE вместо больших IFоберток

Синтаксис:

DROP {PROC | ПРОЦЕДУРА} [ЕСЛИ СУЩЕСТВУЕТ] {[имя_схемы. ] процедура} [, ... n]

Запрос:

DROP PROCEDURE IF EXISTS usp_name

Больше информации здесь


11
if not exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[xxx]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
BEGIN
CREATE PROCEDURE dbo.xxx

где xxxимя процедуры


4

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


Интересный! За пять лет, прошедших с тех пор, как вы опубликовали этот ответ, были ли дальнейшие разработки в методах управления версиями вашей базы данных?
Thomas L Holaday

4

Вы можете написать запрос следующим образом:

IF OBJECT_ID('ProcedureName','P') IS NOT NULL
    DROP PROC ProcedureName
GO

CREATE PROCEDURE [dbo].[ProcedureName]
...your query here....

Чтобы быть более конкретным в приведенном выше синтаксисе:
OBJECT_ID - это уникальный номер идентификатора для объекта в базе данных, он используется внутри SQL Server. Поскольку мы передаем имя процедуры, за которым следует тип объекта P, который сообщает SQL-серверу, что вы должны найти объект с именем имя процедуры, который имеет тип процедуры, т. Е. P

Этот запрос найдет процедуру и, если она доступна, отбросит ее и создаст новую.

Для получения подробной информации о OBJECT_ID и типах объектов посетите: SYS.Objects



0

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

IF OBJECT_ID('ValidateRequestPost') IS NULL
BEGIN
    EXEC ('CREATE PROCEDURE ValidateRequestPost 
    @RequestNo VARCHAR(30),
    @ErrorStates VARCHAR(255) OUTPUT
AS
BEGIN
    SELECT @ErrorStates = @ErrorStates
END')
END

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

0

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

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

//syntax for Create and Alter Proc 
DECLARE @Create NVARCHAR(200) = 'Create PROCEDURE sp_cp_test'; 
DECLARE @Alter NVARCHAR(200) ='Alter PROCEDURE sp_cp_test'; 
//Actual Procedure 
DECLARE @Proc NVARCHAR(200)= ' AS BEGIN select ''sh'' END'; 
//Checking For Sp
IF EXISTS (SELECT * 
           FROM   sysobjects 
           WHERE  id = Object_id('[dbo].[sp_cp_test]') 
                  AND Objectproperty(id, 'IsProcedure') = 1 
                  AND xtype = 'p' 
                  AND NAME = 'sp_cp_test') 
  BEGIN 
      SET @Proc=@Alter + @Proc 

      EXEC (@proc) 
  END 
ELSE 
  BEGIN 
      SET @Proc=@Create + @Proc 

      EXEC (@proc) 
  END 

go 

0

Лучшим вариантом может быть использование такого инструмента, как Red-Gate SQL Compare или SQL Examiner, для автоматического сравнения различий и создания сценария миграции.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.