Depolanmış bir yordamın oluşturulmadan önce var olup olmadığı nasıl kontrol edilir


284

Bir istemci "veritabanı yönetimi" işlevselliğini her çalıştırdığında çalıştırılması gereken bir SQL komut dosyası var. Komut dosyası, istemci veritabanında saklı yordamlar oluşturmayı içerir. Bu istemcilerden bazıları komut dosyasını çalıştırdıktan sonra zaten saklı yordama sahip olabilir ve bazıları olmayabilir. İstemci veritabanına eksik saklı yordamlar eklenmiş olması gerekir, ancak ne kadar T-SQL sözdizimi bükmek için çalışıyorum önemli değil, ben olsun

CREATE / ALTER PROCEDURE ', bir sorgu kümesindeki ilk ifade olmalıdır

Eserler yaratmadan önce bu düşüşü okudum, ama bunu böyle yapmaktan hoşlanmıyorum.

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

CREATE PROCEDURE MyProc
...

Saklı bir yordamın varlığını nasıl denetleyebilir ve yoksa yordamını nasıl oluşturabilirim, ancak varsa değiştirebilirim?


2
hayır, işe yaramaz, çünkü bu, istediğiniz gibi olmadığı iddia edilen saklı bir prosedür oluşturur. görebildiğimiz kadarıyla, bittikten sonra onu düşürmez, bu yüzden kesinlikle terimin tüm yönlerinde saklanır. neden saklı olmayan bir prosedüre ihtiyacınız olduğu önemli değil
David Hedlund

'Depolanmayan' prosedürle ne demek istiyorsun? Örneğinizin yaptığı tek şey saklı bir yordamı yeniden oluşturmaktır; bunun sorunuzla ne ilgisi var?
AakashM

Tamam, işte başlıyoruz. Şey, birçok istemci kullanmak ve bir istemci yazılımımızın sağladığı "veritabanı yönetimi" işlevselliğini her yürüttüğünde iyice çalıştırılması gereken bir büyük SQL komut dosyası var. Bu nedenle, bu istemcilerden bazıları komut dosyasını çalıştırdıktan sonra saklı yordamlara sahip olabilir ve bazıları olmayabilir. Bunun aptalca olduğunu biliyorum, aslında bozulmadan kalmak için bu prosedüre ihtiyacım yok, sadece var olup olmadığını kontrol edebilir ve yoksa yaratabilirim. Ancak, T-SQL sözdizimini ne kadar bükmeye çalıştığım önemli değil, her zaman bir hata var.
Şekillendirici

Komut dosyasını her çalıştırdıklarında, prosedürü tekrar oluşturmaya çalışacaktır (ne yazık ki, her şey oluşturma prosedürü çağrısı da dahil olmak üzere aynı .sql dosyasında komut dosyası olmalıdır). EĞER OLUŞTURULMADIĞINDA, söz dizimi sınırlamaları nedeniyle çalışmaz. Ne yapabilirim?
Şekillendirici

Yanıtlar:


200

Yordam kodunu, sorgu çalıştırabileceğiniz her yerde çalıştırabilirsiniz.

Sonra her şeyi kopyalamanız yeterlidir AS:

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

Bu kod, depolanmış bir işlemin gerçekleştirdiği işlemlerle tamamen aynıdır, ancak veritabanı tarafında depolanmaz.

Bu anonim prosedür denilen şey gibi PL/SQL.

Güncelleme:

Soru başlığınız biraz kafa karıştırıcı.

Yalnızca bir yordam yoksa, kodunuz yeterlidir.

Oluşturma SSMSkomut dosyasında çıktılar şunlardır:

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

Güncelleme:

Şemayı eklerken nasıl yapılacağına örnek:

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

Yukarıdaki örnekte, dbo .

Güncelleme:

SQL Server 2016+ sürümünde,

CREATE OR ALTER PROCEDURE dbo.MyProc


Evet, bu doğrudur, ancak hiçbir prosedür, udf, görünüm ve benzeri herhangi bir işlem işlevselliğini kaybedeceksiniz. (Üzgünüm, düzenledi, kafamda mantıklı geldi X-))
Adriaan Stander

1
Evet, ancak diğer yordamlar içinden yordamları çağırabilir veya dönüşlerini bir tabloya girdi olarak kullanabilirsiniz.
Adriaan Stander

@astander: saklı yordamlardan da anonim kod çağırabilirsiniz. Çıktılarını bir'de kullanmak için , anonim kodla da çalışan veya INSERTkullanmanız gerekir . Tabii ki anonim kodda dezavantajlar var: örneğin, sadece arayanın ayrıcalıkları altında çalışır. OPENROWSETOPENQUERY
Demek istediğim, bir

"Yalnızca bir prosedür yoksa, kodunuz yeterli olacaktır." Ve tam olarak bilmek istedim. Ben gerçek komut dosyası üzerinde SSMS Create kullanmaya çalıştım ama hiçbir işe yaramadı. Ama teşekkürler Quassnoi ve belirsiz soru için özür dilerim.
Şekillendirici

2
CREATE PROC deyimi, dinamik SQL kullanılmadığında toplu işteki tek deyim olmalıdır, böylece bu şekilde uygulandığında DROP / CREATE etrafında bir işlem yapamazsınız. DROP PROC çağrısından sonra bir GO (parti ayırıcı) olmalıdır.
Shiv

450

Bunun zaten cevap olarak işaretlendiğini fark ettim, ama eskiden böyle yapıyorduk:

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

Sadece prosedürü düşürmemek için.


74
Sadece bunun neden iyi bir fikir olduğu hakkında bazı notlar eklemek için: 1) bir damla herhangi bir güvenlik ayarını temizler, 2) bu şekilde yaparak, değiştirme komut dosyası bir nedenle başarısız olursa, sp düşürülmez.
Ryan Guill

10
Bu gerçekten doğru cevap. Söz konusu depolanmış işlemde herhangi bir GRAN kaybını önler.
Andy_Vulhop

7
Saklı yordamın olmadığı zamanın bir anlamı olmaması nedeniyle bu yaklaşıma büyük bir faydası vardır. Güncelleme, başka kişiler, sistemler veya iş parçacıkları tarafından kullanılmaya devam ederken kritik bir sisteme uygulanıyorsa bu çok önemli olabilir. Saklı bir prosedürün geçici olarak düşürülmesinden kaynaklanan hataları izlemek oldukça can sıkıcı olabilir, çünkü çoğaltılması çok zordur.
James

3
Bu, daha önce bahsedilen birçok nedenden ötürü harika bir çözümdür ve şunu eklemek isterim ki, DBA'ların proc meta verilerine (oluşturulduğu tarih gibi) güvenmesi durumunda, bu işlemi proc yapmak yerine sağlam bırakır. her zaman yepyeni. Bunu, genellikle birkaç DB'ye kopyalanması / yayılması gereken kendi proc'larımızı korumak için ekibimin "en iyi uygulaması" na dönüştürmeye çalışıyorum.
NateJ

2
Ayrıca bazı insanlar düşünün istediğinizGRANT komut ifadeleri explicity onlar değiştirmek durumunda ; bu yüzden DROPbunun yerine hala kullanmak için bir gerekçe var ALTER.
Cody Stott

123

Kaldırmadan önce bir veritabanı nesnesinin varlığını kontrol etmenin en basit yolunu arıyorsanız, işte bir yol (örnek, yukarıdaki örnekte olduğu gibi SPROC kullanır, ancak tablolar, dizinler vb. İçin değiştirilebilir ...):

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

Bu hızlı ve zariftir, ancak bunu dikkate almadığı için tüm nesne türlerinde benzersiz nesne adlarına sahip olduğunuzdan emin olmanız gerekir.

Umarım bu yardımcı olur!


62
Daha iyi: EĞER (OBJECT_ID ('MyProcedure', 'P') NULL DEĞİLDİR) DÜŞME PROSEDÜRÜ MyProcedure GO
alerya

33

"Eğer varsa bir prosedürü değiştirmek ve sadece mevcut değilse silmek" istediğinizi biliyorum ama sadece prosedürü her zaman bırakıp yeniden oluşturmak daha basit olduğuna inanıyorum. Yordamı yalnızca zaten varsa nasıl bırakacağınız aşağıda açıklanmıştır:

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

İkinci parametre anlatır OBJECT_IDyalnızca nesnelerin aramaya object_type = 'P', depolanan işlemler olarak

AF = Toplama işlevi (CLR)

C = CHECK kısıtlaması

D = VARSAYILAN (kısıtlama veya bağımsız)

F = FOREIGN KEY kısıtlaması

FN = SQL skaler fonksiyonu

FS = Montaj (CLR) skaler fonksiyon

FT = Montaj (CLR) tablo değerli işlev

IF = SQL satır içi tablo değerli işlev

IT = Dahili tablo

P = SQL Saklı Yordamı

PC = Montaj (CLR) saklı yordamı

PG = Plan rehberi

PK = PRIMARY KEY kısıtlaması

R = Kural (eski tarz, bağımsız)

RF = Çoğaltma-filtre prosedürü

S = Sistem taban tablosu

SN = Eşanlamlı

SO = Dizi nesnesi

TF = SQL tablo değerli işlev

TR = Tetikleyici

Seçeneklerin tam listesini şu yollardan alabilirsiniz:

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

1
TF eksik. Yine de, bu listeyi sağlamak için +1
Crono

Ayrıca TR için Trigger
CarlosOro


23

Çok eski bir yazı olduğunu biliyorum, ancak bu üst arama sonuçlarında göründüğü için SQL Server 2016 SP1'i kullananlar için en son güncellemeyi ekliyor -

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

Bu zaten yoksa bir Saklı Yordam oluşturur, ancak varsa bunu değiştirir.

Referans


1
Bu çok, çok kullanışlı.
AgentFire

Bu sadece SQL Studio'da çalışır - benim için başarısız bir sql dosyasında vurgulamak istiyorum.
James L.

10

DROP IF EXISTS, SQL Server 2016'nın yeni bir özelliğidir

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
Bu SqlServer sözdizimi değil ..., çocuklar aşağı indirmeye başlamadan önce cevabı kaldırmak ve yeni başlayanlar için karışıklığı önlemek için tavsiye.
Pawel Czapski

@PawelCz SQL Server 2016 için geçerlidir ve üstü, cevabı yeniden yazdım. Geri dönüşünüz için teşekkür ederiz!
JayJay

Bu orijinal gönderiye cevap vermiyor. Otomatik olarak bırakma ve yeniden oluşturma ile yalnızca yoksa yaratma arasında ince bir fark vardır. Bir proc'un düşürülmesi, komut dosyasıyla ilişkilendirilmiş olabilecek kendisiyle ilişkili güvenliği düşürür.
Ron

7

Aynı hatayla karşılaştım. Bu konu zaten çoktan ölü olduğunu biliyorum ama "anonim prosedür" yanında başka bir seçenek ayarlamak istiyorum.

Ben böyle çözdüm:

  1. Saklı yordamın mevcut olup olmadığını kontrol edin:

    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. Ancak "CREATE/ALTER PROCEDURE' must be the first statement in a query batch"hala orada. Ben böyle çözdüm:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE -- view procedure function or anything you want ...
  3. Bu kod ile bitirmek:

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

DROP PROSEDÜR gibi sadece 1 kod satırı ise başlangıcı ve bitişi gerekmez ...
Phillip Senn

Uyarı: 'T saklı yordamın var olup olmadığını denetle' işlevi, hangi işlev adını girdiğinizden bağımsız olarak (T-SQL için) her zaman 'var' döndürür. Güvenilmez bir çek.
Ryan Battistone

Daha iyi bir alternatif: EĞER VARSA (Sys.procedures NEREDEN 1 SEÇİNİZ = = name_of_table_as_seen_in_sysprocedures ') BEGIN' durum 'olarak -1 seçin END
Ryan Battistone

5

İşte bir yöntem ve bu şekilde kullanmanın arkasında bir neden var. Depolanan proc düzenlemek o kadar güzel değil ama artıları ve eksileri vardır ...

GÜNCELLEME: Bu aramanın tamamını bir TRANSACTION işlemine de ekleyebilirsiniz. Tek bir işlemde saklanan veya geri dönüşü gerçekleştirebilecek birçok saklı yordam dahil. Bir işlemde kaydırma yapmanın bir diğer avantajı, saklı yordam READ UNCOMMITTED işlem yalıtım düzeyini kullanmadığı sürece her zaman diğer SQL bağlantıları için var olmasıdır!

1) Değişiklikleri bir süreç kararı olarak önlemek. Süreçlerimiz her zaman OLUŞTURMADAN SONRA VARSA. Yeni PROC'un istenen proc olduğunu varsaymakla aynı modeli yaparsanız, altlar için yemek yapmak biraz daha zordur, çünkü EĞER VARSA BAŞKA BİR OLUŞTURUNUZ.

2) CREATE / ALTER komutunu toplu işteki ilk çağrı olarak koymanız gerekir, böylece dinamik SQL dışındaki bir işlemde bir dizi işlem güncellemesini kapatamazsınız. Temel olarak bir yordam güncellemeleri yığını çalıştırmak veya bir DB yedeklemesini geri yüklemeden hepsini geri almak istiyorsanız, bu her şeyi tek bir toplu işte yapmanın bir yoludur.

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 server 2008'den itibaren " INFORMATION_SCHEMA.ROUTINES"

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

3

Görünüşe göre oy vermek veya yorum yapmak için gereken itibara sahip değilim, ancak Geoff'un EXEC'i (sp_executesql daha iyi olabilir) kullanarak cevabının kesinlikle gitmenin yolu olduğunu söylemek istedim. Saklı yordamın düşürülmesi ve yeniden oluşturulması, işin sonunda yapılmasını sağlar, ancak saklı yordamın hiç olmadığı bir an vardır ve bu çok kötü olabilir, özellikle de bu, tekrar tekrar çalıştırın. Bir arka plan iş parçacığı bir IF EXISTS DROP yapıyordu çünkü benim uygulama ile ilgili her türlü sorun yaşıyordu ... aynı anda başka bir iş parçacığı saklı yordamı kullanmaya çalışıyordu.


3

** T-Sql'de depolanan bir işlemi bırakmanın ve yeniden oluşturmanın en basit yolu **

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

İşte kullandığım komut. Bununla beraber, saklanan procs'ları gereksiz yere düşürmekten ve yeniden yaratmaktan kaçınırım.

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


1

neden basit yoldan gitmiyorsun

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

    CREATE Procedure uspBlackListGetAll

..........


Burada LIKE% ifadesi kullanmak kötü bir fikir. OP'nin uspBlackListGetAll_V2 gibi başka bir sproc bırakmasını istemiyorsa ne olurdu?
Dave Hogan

@DaveHogan katılıyorum. Ancak o koymadı %, bu yüzden bir LIKEdavranır=
Diego Jancic

1
Düzenlenen geçmişe bakarsanız, başlangıçta bir '%' ile olduğunu göreceksiniz
Dave Hogan


0

Merak ediyorum! Neden bütün sorguyu yazmıyorum

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

zaten ilk iki yordam zaten var sql sorgusu çalışacak sorgu ilk iki yordamlar hata verecektir ama yine de SQl kendisi zaten var olan şey dikkat çeken bu her zaman tüm yapmak ne benim istemciler!


-2

'Proc adınız' () OLMADIĞINDA OLUŞTURMA İŞLEMİ BAŞLATIN ... END


prosedür varsa bu hiçbir şey yapmaz. İstekte bulunan, varsa prosedürü değiştirmek istiyor, eğer oluşturuyorsa oluşturun.
Randy Gamage
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.