Как проверить, существует ли хранимая процедура до ее создания
У меня есть 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'
Ответ 5
С 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
Ответ 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
Ответ 14
DROP IF EXISTS - это новая функция SQL Server 2016
https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/
DROP PROCEDURE IF EXISTS dbo.[procname]
Ответ 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