Як перевірити, чи існує збережена процедура перед її створенням


283

У мене є сценарій 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
...

Як я можу додати перевірку на наявність збереженої процедури та створити її, якщо вона не існує, але змінити її, якщо вона існує?


2
ні, це не працює, оскільки це створює збережену процедуру, яка нібито не є тим, що потрібно. з того, що ми бачимо, він також не скидає його після завершення, тому він точно зберігається у всіх аспектах цього терміна. це НЕ має значення , чому вам потрібна процедура нон збереженими
Девід Хедлунд

Що ви маєте на увазі під процедурою, що не зберігається? Все, що ваш зразок, це відтворити збережену процедуру; що це стосується вашого питання?
AakashM

Гаразд, там ми їдемо. Річ у тому, що у мене є ВЕЛИЧИЙ скрипт SQL, який використовують багато клієнтів, і його потрібно ретельно виконувати щоразу, коли клієнт виконує функцію "управління базами даних", яку надає наше програмне забезпечення. Тому деякі з цих клієнтів, можливо, вже зберігають процедуру після запуску сценарію, а деякі можуть. Я знаю, що це нерозумно, мені фактично не потрібна ця процедура, щоб вона залишалася непотрібною, я можу просто перевірити, чи існує вона, і створити її, якщо її немає. Однак, не важливо, наскільки я намагаюся зігнути синтаксис T-SQL, завжди є помилка.
Шапер

Кожен раз, коли вони запустять сценарій, він буде намагатися створити процедуру заново (на жаль, все має бути сценарієм у тому ж файлі .sql, включаючи виклик процедури створення). ЯКЩО НЕ ІСНУЄТЬСЯ, ЩО CREATE не працює через синтаксичні обмеження. Що я можу зробити?
Шапер

Відповіді:


199

Ви можете запустити процедурний код у будь-якому місці, де ви зможете запустити запит.

Просто скопіюйте все після 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


Так, це правда, але ви втратите всю функціональну функціональність, оскільки жодні процедури, udfs, представлення даних тощо не зберігатимуться для дзвінків із запитів. (Вибачте, відредагував це, це мало сенс у моїй голові X-))
Адріан Штендер

1
Так, але ви можете викликати процедури в межах інших процедур або використовувати їх повернення як вхід до таблиці.
Адріан Стандер

@astander: ви також можете подзвонити анонімний код із збережених процедур. Для використання їх результатів у програмі INSERTвам потрібно використовувати OPENROWSETабо OPENQUERYякий працює з анонімним кодом. Звичайно, в анонімному коді є недоліки: наприклад, він працює лише під привілеями абонента. Моя думка полягає в тому, що це можливо, а не бажаний спосіб робити :)
Quassnoi

"Якщо вам потрібно створити процедуру лише тоді, коли вона не існує, ваш код просто відмінний." І саме це я хотів знати. Я намагався використовувати SSMS Create для фактичного сценарію, але це не принесло користі. Але дякую Квасной, і мені шкода незрозумілого питання.
Шапер

2
Оператор CREATE PROC повинен бути єдиним у пакетній заяві, коли не використовується динамічний SQL, тому ви не можете обернути транзакцію навколо DROP / CREATE, коли реалізовано таким чином. Після виклику DROP PROC повинен бути GO (роздільний пакет).
Шив

449

Я усвідомлюю, що це вже було позначено як відповідь, але ми звикли робити це так:

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

Тільки, щоб не припиняти процедуру.


74
Просто додати кілька записок про те, чому це гарна ідея: 1) крапля очистить будь-які параметри безпеки; 2) зробивши це таким чином, якщо сценарій зміни з якоїсь причини не вдасться, програма sp не буде відкинута.
Райан Гілл

10
Це справді правильна відповідь. Це дозволяє уникнути втрати будь-яких ГРАНТ на збереженому процесорі.
Andy_Vulhop

7
Такий підхід має величезну користь у тому, що немає моменту, коли зберігається процедура не існує. Це може бути вирішальним, якщо оновлення застосовується до критичної системи, поки воно ще використовується іншими людьми, системами або потоками. Відстеження помилок, викликаних миттєвим відкиданням збереженої процедури, може бути дуже неприємним, оскільки їх дуже важко відтворити.
Джеймс

3
Це чудове рішення з багатьох згаданих причин, і я просто хотів би додати, що у випадку, якщо DBA покладаються на метадані Proc (такі як створені дати), це залишає цілі речі недоторканими, замість того, щоб робити процедуру абсолютно кожен раз. Я намагаюся, щоб це перетворилося на "найкращу практику" моєї команди щодо підтримки наших власних програм, які, як правило, повинні бути скопійовані / розповсюджені в декілька БД.
NateJ

2
Також врахуйте, що деякі люди хочуть, щоб GRANTвиразність тверджень у сценарії була змінена ; тому все ж є виправдання використовувати DROPзамість цього ALTER.
Коді Стотт

123

Якщо ви шукаєте найпростіший спосіб перевірити наявність об'єкта бази даних перед тим, як видалити його, ось один спосіб (наприклад, використовується SPROC, як і ваш приклад вище, але його можна змінити для таблиць, індексів тощо):

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

Це швидко та елегантно, але вам потрібно переконатися, що у вас є унікальні назви об’єктів для всіх типів об'єктів, оскільки це не враховує.

Сподіваюся, це допомагає!


62
Що краще: ЯКЩО (OBJECT_ID ('MyProcedure', 'P') НЕ НУЛЬНИЙ) ПРОЦЕДУРА ДРОПУВАННЯ MyProcedure GO
alerya

33

Я знаю, що ви хочете "змінити процедуру, якщо вона існує, і видалити її лише, якщо її не існує", але я вважаю, що простіше просто завжди відмовитись від процедури, а потім знову створити її. Ось як відмовитися від процедури, лише якщо вона вже існує:

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

Другий параметр вказує OBJECT_IDтільки шукати об'єкти з object_type = 'P', які збережених процедур:

AF = Функція сукупності (CLR)

C = ПЕРЕВІРИТИ обмеження

D = ЗАМОВЛЕННЯ (обмеження або автономність)

F = обмеження закордонного ключа

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

FS = скалярна функція збірки (CLR)

FT = функція, що оцінюється за таблицею (CLR)

IF = функція вбудованої таблиці в значення SQL

IT = Внутрішня таблиця

P = Збережена процедура SQL

PC = Зберігання (CLR) збереженої процедури

PG = Посібник з плану

ПК = ПЕРШИЧНЕ КЛЮЧОВЕ обмеження

R = правило (старий стиль, автономний)

RF = Реплікація-фільтр-процедура

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

SN = Синонім

SO = Послідовність об’єкта

TF = SQL-значення з функцією таблиці

TR = тригер

Повний список опцій можна отримати за допомогою:

SELECT name 
FROM master..spt_values
WHERE type = 'O9T'

1
TF відсутній. Все-таки +1 за надання цього списку
Crono

Також TR для Trigger
CarlosOro


23

Я знаю, що це дуже стара публікація, але оскільки вона з’являється у головних результатах пошуку, отже, додаємо останнє оновлення для тих, хто використовує SQL Server 2016 SP1 -

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

Це створює процедуру зберігання, якщо вона ще не існує, але змінює її, якщо вона існує.

Довідково


1
Це так, так корисно.
AgentFire

Я хочу наголосити, що це працює лише в SQL Studio - у файлі sql мені це не вдається.
Джеймс Л.

10

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]

1
це не синтаксис SqlServer ..., порада видалити відповідь перед тим, як хлопці почнуть сприймати та уникати плутанини для новачків.
Pawel Czapski

@PawelCz він дійсний для SQL Server 2016 і новіших версій, я переформулював відповідь. Дякуємо за відгук!
JayJay

Це не відповідає оригінальній публікації. Існує тонка різниця між автоматичним випаданням і відтворенням і створенням лише, якщо його не існує. Якщо вимкнути програму, ви втратите пов’язану з нею безпеку, яка, можливо, була сценарієм.
Рон

7

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

Я вирішив це так:

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

Вам не потрібно починати та закінчувати, якщо це лише 1 рядок коду, як ПРОЦЕДУРА ДРОПУ ...
Phillip Senn

Попередження: функція "перевірити, чи існує збережена процедура", завжди буде повертати "існує", незалежно від того, яке ім'я функції ви ввели (для T-SQL). Це ненадійний чек.
Райан Баттістон

Краща альтернатива: ЯКЩО ВИНАГАЄТЬСЯ (ВИБІР 1 З sys.procedures WHERE name = 'name_of_table_as_seen_in_sysprocedures') ПОЧАК виберіть -1 як 'статус' КІН
Ryan Battistone

5

Ось метод і деякі міркування щодо його використання таким чином. Це не так красиво, щоб редагувати збережену процедуру, але є плюси і мінуси ...

ОНОВЛЕННЯ: Ви також можете перетворити весь цей виклик у ПЕРЕКЛАД. Включення багатьох збережених процедур в одну транзакцію, яка може зробити все або відкат. Ще одна перевага обгортання транзакції - збережена процедура завжди існує для інших підключень SQL до тих пір, поки вони не використовують рівень ізоляції транзакцій READ UNCOMMITTED!

1) Щоб уникнути змін просто як рішення процесу. Наші процеси завжди полягають у тому, щоби ЯКЩО ІСНУЄТЬСЯ ТОПЛИ ТВОРИТИ Якщо ви зробите ту саму схему, якщо припустити, що новий PROC є бажаною процедурою, задоволення змін зміниться трохи складніше, оскільки у вас виникне ЯКЩО БУДЕ ЗАЛИШИТЬ БІЛЬШЕ СТВОРЕННЯ.

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

5

На сервері Sql з 2008 року ви можете використовувати " INFORMATION_SCHEMA.ROUTINES"

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

3

Я, мабуть, не маю репутації, необхідної для голосування чи коментарів, але я просто хотів сказати, що відповідь Джеффа за допомогою EXEC (sp_executesql, можливо, буде кращим) - це безумовно шлях. Видалення та повторне створення збереженої процедури зрештою виконує роботу, але настає момент, коли збережена процедура взагалі не існує, і це може бути дуже погано, особливо якщо це щось, що буде бігати повторно. У мене виникли всілякі проблеми з моїм додатком, тому що фонова нитка робила, ЯКЩО ВІДКЛЮЧАЄТЬСЯ ... СТВОРИТИ в той же час інший потік намагався використовувати збережену процедуру.


3

** Найпростіший спосіб скинути і відтворити збережений доступ у 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

3

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

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

2

Перевірте, чи існує ІС на наявність збереженої процедури

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

Перевірте, чи існує ІСІ на тригер, функцію також, натиснувши посилання нижче http://www.gurujipoint.com/2017/05/check-if-exist-for-trigger-function-and.html


1

чому ти не підеш таким простим шляхом

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

    CREATE Procedure uspBlackListGetAll

..........


Тут погана ідея використовувати висловлювання LIKE%. Що робити, якщо в ОП був інший проріз, такий як uspBlackListGetAll_V2, який вони не хочуть скидати?
Дейв Хоган

@DaveHogan Я згоден. Однак він не поставив %, тому LIKEведе себе як=
Дієго Янчич

1
@DiegoJancic, якщо подивитися на відредаговану історію, ви побачите, що вона спочатку була "%"
Дейв Хоган

0

На додаток до відповіді від @Geoff я створив простий інструмент, який генерує SQL-файл, який містить висловлювання для збережених процедур, переглядів, функцій та тригерів.

Див. Розділ MyDbUtils @ CodePlex . введіть тут опис зображення


1
Я думаю, студія управління вже дає такий інструмент. Це називається "Створення сценаріїв"
Hybris95

0

Цікаво! Чому я не записую такий запит, як

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 сам піклується про те, що вже існує, це те, що я завжди роблю всім своїм клієнти!


-2

Створіть процедуру, ЯКЩО НЕ ІСНУЄТЬСЯ "Ваше ім'я" () ПОЧАТОК ... КРАЙ


це не зробить нічого, якщо процедура існує. Запитувач хоче змінити процедуру, якщо вона існує, створити її, якщо ні.
Ренді Геймж
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.