Cara memeriksa apakah ada prosedur yang tersimpan sebelum membuatnya

284

Saya memiliki skrip SQL yang harus dijalankan setiap kali klien menjalankan fungsionalitas "manajemen basis data". Script termasuk membuat prosedur tersimpan pada basis data klien. Beberapa klien ini mungkin sudah memiliki prosedur tersimpan saat menjalankan skrip, dan beberapa mungkin tidak. Saya perlu memiliki prosedur tersimpan yang hilang ditambahkan ke database klien, tetapi tidak masalah seberapa banyak saya mencoba untuk menekuk sintaks T-SQL, saya mendapatkan

CREATE / ALTER PROCEDURE 'harus menjadi pernyataan pertama dalam kumpulan permintaan

Saya sudah membaca dropping itu sebelum membuat karya, tapi saya tidak suka melakukannya dengan cara itu.

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

CREATE PROCEDURE MyProc
...

Bagaimana saya bisa menambahkan memeriksa keberadaan prosedur tersimpan dan membuatnya jika tidak ada tetapi mengubahnya jika memang ada?

Pembentuk
sumber
2
tidak itu tidak berfungsi, karena itu menciptakan prosedur tersimpan yang diduga bukan yang Anda inginkan. dari apa yang bisa kita lihat, itu tidak drop setelah selesai, jadi, itu pasti disimpan dalam semua aspek istilah. itu tidak relevan mengapa Anda memerlukan prosedur yang tidak disimpan
David Hedlund
Apa yang Anda maksud dengan prosedur 'tidak disimpan'? Semua sampel Anda lakukan adalah membuat ulang prosedur yang tersimpan; apa hubungannya ini dengan pertanyaan anda?
AakashM
Oke, ini dia. Masalahnya, saya memiliki skrip SQL BESAR yang digunakan banyak klien dan harus dijalankan secara menyeluruh setiap kali klien menjalankan fungsionalitas "manajemen basis data" yang disediakan oleh perangkat lunak kami. Jadi beberapa klien ini mungkin sudah memiliki prosedur yang tersimpan saat menjalankan skrip, dan beberapa mungkin tidak. Saya tahu ini bodoh, saya sebenarnya tidak memerlukan prosedur ini untuk tetap tidak tersimpan, saya hanya dapat memeriksa apakah ada dan membuatnya jika tidak. Namun, tidak masalah seberapa banyak saya mencoba untuk menekuk sintaks T-SQL, selalu ada kesalahan.
The Shaper
Setiap kali mereka menjalankan skrip, ia akan mencoba membuat prosedur lagi (sayangnya, semuanya harus ditulis dalam file .sql yang sama termasuk panggilan prosedur buat). JIKA TIDAK ADA KEMUDIAN MENCIPTAKAN tidak berfungsi karena keterbatasan sintaksis. Apa yang dapat saya?
The Shaper
3
Kemungkinan duplikat stackoverflow.com/questions/937908/…
Michael Freidgeim

Jawaban:

200

Anda dapat menjalankan kode prosedural di mana saja Anda dapat menjalankan kueri.

Cukup salin semuanya setelah AS:

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

Kode ini melakukan hal yang persis sama dengan proc yang disimpan, tetapi tidak disimpan di sisi basis data.

Itu seperti apa yang disebut prosedur anonim PL/SQL.

Memperbarui:

Judul pertanyaan Anda agak membingungkan.

Jika Anda hanya perlu membuat prosedur jika tidak ada, maka kode Anda baik-baik saja.

Inilah yang SSMSdihasilkan dalam skrip buat:

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

Memperbarui:

Contoh cara melakukannya saat menyertakan skema:

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

Dalam contoh di atas, dbo adalah skema.

Memperbarui:

Di SQL Server 2016+, Anda bisa melakukannya

CREATE OR ALTER PROCEDURE dbo.MyProc

Quassnoi
sumber
Ya ini benar, tetapi Anda akan kehilangan semua fungsi prosedural karena tidak ada prosedur, udfs, pandangan dan semacamnya akan disimpan untuk dipanggil dari dalam kueri. (Maaf, diedit, itu masuk akal di kepalaku X-))
Adriaan Stander
1
Ya, tetapi Anda bisa memanggil prosedur dari dalam prosedur lain, atau menggunakan pengembaliannya sebagai input ke tabel.
Adriaan Stander
@astander: Anda dapat memanggil kode anonim dari prosedur tersimpan juga. Untuk menggunakan output mereka dalam INSERT, Anda harus menggunakan OPENROWSETatau OPENQUERYyang berfungsi dengan kode anonim juga. Tentu saja ada kekurangan dalam kode anonim: misalnya, itu hanya berjalan di bawah hak si penelepon. Maksud saya adalah bahwa itu mungkin, bukan cara yang disukai dalam melakukan hal-hal :)
Quassnoi
"Jika Anda hanya perlu membuat prosedur jika tidak ada, maka kode Anda baik-baik saja." Dan itulah yang ingin saya ketahui. Saya mencoba menggunakan SSMS Buat pada skrip yang sebenarnya tetapi tidak ada gunanya. Tapi terima kasih Quassnoi, dan aku minta maaf tentang pertanyaan yang tidak jelas.
The Shaper
2
Pernyataan CREATE PROC harus menjadi satu-satunya pernyataan dalam kumpulan ketika tidak menggunakan SQL dinamis sehingga Anda tidak dapat membungkus transaksi di sekitar DROP / CREATE saat diterapkan dengan cara ini. Harus ada GO (pemisah batch) setelah panggilan DROP PROC.
Shiv
450

Saya menyadari ini sudah ditandai sebagai dijawab, tetapi kami biasa melakukannya seperti ini:

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

Hanya untuk menghindari menjatuhkan prosedur.

Geoff
sumber
74
Hanya untuk menambahkan beberapa catatan tentang mengapa ini adalah ide yang baik: 1) setetes akan menghapus pengaturan keamanan, 2) dengan melakukannya dengan cara ini, jika skrip alter gagal karena suatu alasan, sp tidak akan dijatuhkan.
Ryan Guill
10
Ini benar-benar jawaban yang benar. Ini menghindari kehilangan HIBAH pada proc yang tersimpan tersebut.
Andy_Vulhop
7
Ada manfaat besar untuk pendekatan ini karena tidak ada titik waktu ketika prosedur tersimpan tidak ada. Ini bisa menjadi sangat penting jika pembaruan diterapkan ke sistem kritis ketika sedang digunakan oleh orang lain, sistem, atau utas. Melacak kesalahan yang disebabkan oleh sesaat menjatuhkan prosedur yang tersimpan bisa sangat menjengkelkan karena sangat sulit untuk direproduksi.
James
3
Ini adalah solusi yang bagus untuk banyak alasan yang telah disebutkan, dan saya hanya ingin menambahkan bahwa, jika DBA bergantung pada meta-data proc (seperti tanggal-dibuat), ini membuat barang tetap utuh, alih-alih membuat baru setiap saat. Saya mencoba mengubah ini menjadi "praktik terbaik" tim saya untuk mempertahankan procs kami sendiri, yang biasanya harus disalin / diperbanyak ke beberapa DB.
NateJ
2
Juga mempertimbangkan bahwa beberapa orang ingin yang GRANTpernyataan eksplisit dalam naskah dalam kasus mereka berubah ; jadi masih ada pembenaran untuk menggunakan DROPbukan ALTER.
Cody Stott
123

Jika Anda mencari cara paling sederhana untuk memeriksa keberadaan objek basis data sebelum menghapusnya, berikut ini salah satu caranya (contoh menggunakan SPROC, seperti contoh Anda di atas tetapi dapat dimodifikasi untuk tabel, indeks, dll ...):

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

Ini cepat dan elegan, tetapi Anda perlu memastikan Anda memiliki nama objek unik di semua jenis objek karena tidak memperhitungkannya.

Saya harap ini membantu!

MrChips
sumber
62
Itu lebih baik: JIKA (OBJECT_ID ('MyProcedure', 'P') BUKAN NULL) PROSEDUR DROP MyProcedure GO
alerya
33

Saya tahu Anda ingin "mengubah prosedur jika ada dan hanya menghapusnya jika tidak ada" tapi saya percaya lebih mudah untuk selalu meninggalkan prosedur dan kemudian membuatnya kembali. Berikut cara membatalkan prosedur hanya jika sudah ada:

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

Parameter kedua memberi tahu OBJECT_IDuntuk hanya mencari objek dengan object_type = 'P', yang merupakan prosedur tersimpan:

AF = Fungsi agregat (CLR)

C = PERIKSA kendala

D = DEFAULT (kendala atau berdiri sendiri)

F = Kendala KUNCI ASING

FN = Fungsi skalar SQL

FS = Majelis (CLR) fungsi skalar

FT = Majelis (CLR) fungsi bernilai tabel

IF = fungsi bernilai tabel inline SQL

IT = Tabel internal

P = Prosedur yang Disimpan SQL

Prosedur tersimpan PC = Assembly (CLR)

PG = Panduan rencana

PK = Kendala KUNCI UTAMA

R = Aturan (gaya lama, berdiri sendiri)

RF = Prosedur-replikasi-filter

S = Tabel dasar sistem

SN = Sinonim

SO = Obyek urutan

TF = SQL table bernilai fungsi

TR = Pemicu

Anda bisa mendapatkan daftar opsi lengkap melalui:

SELECT name 
FROM master..spt_values
WHERE type = 'O9T'
Michael Currie
sumber
1
TF tidak ada. Namun, +1 untuk memberikan daftar ini
Crono
Juga TR untuk Pemicu
CarlosOro
23

Saya tahu ini adalah posting yang sangat lama, tetapi karena ini muncul di hasil pencarian teratas maka menambahkan pembaruan terbaru untuk mereka yang menggunakan SQL Server 2016 SP1 -

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

Ini menciptakan Prosedur Tersimpan jika belum ada, tetapi mengubahnya jika ada.

Referensi

gkb
sumber
1
Ini sangat, sangat berguna.
AgentFire
Saya ingin menekankan ini hanya bekerja di SQL Studio - dalam file sql gagal untuk saya.
James L.
10

DROP JIKA ADA adalah fitur baru dari 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]
JayJay
sumber
1
ini bukan sintaks SqlServer ..., saran untuk menghapus jawaban sebelum orang mulai downvoting dan untuk menghindari kebingungan bagi pemula.
Pawel Czapski
@ PamCz ini valid untuk SQL Server 2016 dan lebih tinggi, saya menulis ulang jawabannya. Terima kasih untuk umpan baliknya!
JayJay
Ini tidak menjawab pos asli. Ada perbedaan tipis antara menjatuhkan dan membuat ulang secara otomatis dan hanya membuat jika tidak ada. Menjatuhkan proc akan menurunkan keamanan yang terkait dengannya, yang mungkin telah dituliskan.
Ron
7

Saya memiliki kesalahan yang sama. Saya tahu utas ini sudah hampir mati, tetapi saya ingin menetapkan opsi lain selain "prosedur anonim".

Saya menyelesaikannya seperti ini:

  1. Periksa apakah prosedur yang tersimpan ada:

    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. Namun "CREATE/ALTER PROCEDURE' must be the first statement in a query batch"masih ada. Saya menyelesaikannya seperti ini:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE -- view procedure function or anything you want ...
  3. Saya berakhir dengan kode ini:

    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 ...
Oaxas
sumber
Anda tidak perlu awal dan akhir jika hanya 1 baris kode seperti PROPEDUR DROP ...
Phillip Senn
Peringatan: fungsi 'centang jika prosedur tersimpan' akan selalu kembali 'ada', tidak peduli nama fungsi apa yang Anda masukkan (untuk T-SQL). Ini adalah pemeriksaan yang tidak dapat diandalkan.
Ryan Battistone
Alternatif yang lebih baik: JIKA ADA (SELECT 1 FROM sys.procedures WHERE name = 'name_of_table_as_seen_in_sysprocedures') DIMULAI pilih -1 sebagai 'status' AKHIR
Ryan Battistone
5

Inilah metode dan beberapa alasan di balik menggunakannya dengan cara ini. Mengedit proc yang disimpan tidaklah seindah tetapi ada pro dan kontra ...

PEMBARUAN: Anda juga dapat membungkus seluruh panggilan ini dalam suatu TRANSAKSI. Termasuk banyak prosedur tersimpan dalam satu transaksi yang semuanya dapat melakukan atau mengembalikan semua. Keuntungan lain dari pembungkus dalam suatu transaksi adalah prosedur tersimpan selalu ada untuk koneksi SQL lainnya selama mereka tidak menggunakan tingkat isolasi transaksi BACA TIDAK DIKOMPITASI!

1) Untuk menghindari perubahan hanya sebagai keputusan proses. Proses kami adalah untuk selalu JIKA ADA DROP KEMUDIAN BUAT. Jika Anda melakukan pola yang sama dengan menganggap PROC baru adalah proc yang diinginkan, melayani perubahan sedikit lebih sulit karena Anda akan memiliki JIKA ADA MENGUBAH ELSE BUAT.

2) Anda harus meletakkan CREATE / ALTER sebagai panggilan pertama dalam batch sehingga Anda tidak dapat membungkus urutan pembaruan prosedur dalam transaksi di luar SQL dinamis. Pada dasarnya jika Anda ingin menjalankan seluruh tumpukan pembaruan prosedur atau mengembalikan semuanya tanpa mengembalikan cadangan DB, ini adalah cara untuk melakukan semuanya dalam satu batch.

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
Pisau
sumber
5

Di Sql server 2008 dan seterusnya, Anda dapat menggunakan " INFORMATION_SCHEMA.ROUTINES"

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES 
  WHERE ROUTINE_NAME = 'MySP'
        AND ROUTINE_TYPE = 'PROCEDURE') 
Romil Kumar Jain
sumber
3

Saya tampaknya tidak memiliki reputasi yang diperlukan untuk memilih atau berkomentar, tetapi saya hanya ingin mengatakan bahwa jawaban Geoff menggunakan EXEC (sp_executesql mungkin lebih baik) jelas merupakan cara yang harus dilakukan. Menjatuhkan dan kemudian menciptakan kembali prosedur tersimpan menyelesaikan pekerjaan pada akhirnya, tetapi ada saat di mana prosedur tersimpan tidak ada sama sekali, dan itu bisa sangat buruk, terutama jika ini adalah sesuatu yang akan menjadi jalankan berulang kali. Saya mengalami segala macam masalah dengan aplikasi saya karena utas latar sedang melakukan JIKA ADA DROP ... BUAT pada saat yang sama utas lain mencoba menggunakan prosedur tersimpan.

James
sumber
3

** Cara paling sederhana untuk menjatuhkan dan membuat ulang proc yang tersimpan di T-Sql adalah **

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
Rennish Joseph
sumber
3

Berikut ini skrip yang saya gunakan. Dengan itu, saya menghindari menjatuhkan dan membuat ulang procs yang disimpan secara tidak perlu.

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
myroslav
sumber
2

Periksa JIKA Ada Prosedur yang Disimpan

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

Periksa JIKA Ada untuk Pemicu, Berfungsi juga dengan mengklik tautan di bawah http://www.gurujipoint.com/2017/05/check-if-exist-for-trigger-function-and.html

Jatin Phulera
sumber
1

kenapa kamu tidak pergi dengan cara sederhana seperti

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

    CREATE Procedure uspBlackListGetAll

..........

dnxit
sumber
Gagasan buruk untuk menggunakan pernyataan LIKE% di sini. Bagaimana jika OP memiliki sproc lain seperti uspBlackListGetAll_V2 yang tidak ingin mereka buang?
Dave Hogan
@DaveHogan saya setuju. Namun dia tidak menempatkan %, jadi LIKEberperilaku sebagai=
Diego Jancic
1
@DiegoJancic jika Anda melihat sejarah yang diedit Anda akan melihatnya pada awalnya dengan '%'
Dave Hogan
0

Selain jawaban dari @ Geoff saya telah membuat alat sederhana yang menghasilkan file SQL yang pernyataan untuk Prosedur Tersimpan, Tampilan, Fungsi dan Pemicu.

Lihat MyDbUtils @ CodePlex . masukkan deskripsi gambar di sini

Stef Heyenrath
sumber
1
Saya pikir Management Studio sudah memberikan alat tersebut. Ini disebut "Hasilkan skrip"
Hybris95
0

Aku penasaran! Mengapa saya tidak menulis seluruh kueri seperti

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

saya sudah tahu bahwa dua prosedur pertama sudah ada sql akan menjalankan kueri akan memberikan kesalahan dari dua prosedur pertama tetapi masih akan membuat prosedur terakhir SQl sendiri mengurus apa yang sudah ada ini adalah apa yang selalu saya lakukan untuk semua saya klien!

Shaikh Noman Nasir
sumber
-2

BUAT Prosedur JIKA TIDAK ADA 'Nama proc Anda' () DIMULAI ... AKHIR

Wartari
sumber
ini tidak akan melakukan apa-apa jika prosedur itu ada. Pemohon ingin mengubah prosedur jika ada, buat jika tidak.
Randy Gamage