Buat fungsi baru dengan kode jika tidak ada

15

Saya ingin membuat fungsi baru dengan skrip di database saya. Kode skrip di bawah ini:

IF Exists(Select * From sys.sysobjects A Where A.name =N'fn_myfunc' and xtype=N'FN') return;

CREATE FUNCTION fn_myfunc ()
returns varchar(10)
AS Begin
...
End

Tetapi ketika saya menjalankan skrip di atas, SQL Server mengembalikan kesalahan:

'CREATE FUNCTION' must be the first statement in a query batch.
mehdi lotfi
sumber

Jawaban:

16

Pembaruan Jan 2017 - SQL Server 2016+ / Azure SQL Database

SQL Server 2016 dan versi saat ini dari Azure SQL Database sekarang memiliki sintaks berikut untuk fungsi, prosedur, tabel, database, dll. ( DROP IF EXISTS):

DROP FUNCTION IF EXISTS dbo.fn_myfunc;

Dan SQL Server 2016 Paket Layanan 1 menambahkan fungsionalitas yang lebih baik untuk modul (fungsi, prosedur, pemicu, tampilan) yang berarti tidak ada kehilangan izin atau dependensi ( CREATE OR ALTER):

CREATE OR ALTER FUNCTION dbo.fn_myfunc ...

Kedua peningkatan sintaksis ini dapat menyebabkan skrip yang lebih sederhana digunakan untuk kontrol sumber, penyebaran, dll.

Tetapi, jika Anda menggunakan ...


Versi yang lebih lama

Anda perlu melakukan apa yang SQL Server lakukan ketika Anda skrip ini dari Management Studio:

IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE type = 'FN' AND name = 'fn_myfunc')
BEGIN
    DECLARE @sql NVARCHAR(MAX);
    SET @sql = N'CREATE FUNCTION ...';
    EXEC sp_executesql @sql;
END

Atau Anda bisa mengatakan:

BEGIN TRY
    DROP FUNCTION dbo.fn_myfunc;
END TRY
BEGIN CATCH
    PRINT 'Function did not exist.';
END CATCH
GO
CREATE FUNCTION...

Atau Anda bisa mengatakan:

DROP FUNCTION dbo.fn_myfunc;
GO
CREATE FUNCTION...

(Di sini Anda akan mendapatkan pesan kesalahan jika fungsi tersebut belum ada, tetapi skrip akan melanjutkan dari GO berikutnya, jadi apakah drop berfungsi atau tidak, fungsi tersebut masih akan (kembali) dibuat.)

Perhatikan bahwa jika Anda menjatuhkan fungsi dan membuatnya kembali, Anda akan kehilangan izin dan informasi ketergantungan yang potensial.

Aaron Bertrand
sumber
1
jadi tidak ada kata kunci $$ BUAT ATAU GANTI $$? kasihan.
zinking
@ memikirkan tidak, tapi mungkin dalam versi masa depan. Harap beri suara / komentar: connect.microsoft.com/SQLServer/feedback/details/127219/…
Aaron Bertrand
1
@AaronBertrand Ide bagus untuk memilihnya, tetapi tautannya rusak
kebiru
@Bluish ya maaf, mereka menghapus item antara tiga tahun yang lalu ketika saya memposting tautan dan sekarang ... Coba connect.microsoft.com/SQLServer/feedback/details/344991/… atau connect.microsoft.com/SQLServer/feedback / details / 351217 / ...
Aaron Bertrand
1

Kesalahannya cukup jelas. Ada beberapa cara untuk memperbaikinya.

  1. Pisahkan skrip menjadi beberapa kumpulan di Management Studio menggunakan GOkata kunci semu, dan DROP/ CREATEobjek. (Perhatikan bahwa kata kunci itu sendiri dapat diubah di opsi Management Studio, tapi ini adalah pengaturan de facto, jadi saya sarankan biarkan saja).

    Saat Anda menjalankan skrip (atau bagian skrip yang dipilih), Studio Manajemen memisahkan setiap skrip skrip antara GOs, dan secara berurutan mengirimkan bagian-bagian ke SQL Server sebagai kumpulan terpisah.

  2. Gunakan SQL dinamis untuk mengirim kumpulan terpisah dari dalam kumpulan lain.

    Ini adalah metode yang disukai, karena dengan demikian skrip Anda tidak bergantung pada fungsi eksternal untuk mengeksekusi dengan benar. Misalnya, jika aplikasi Anda memiliki program pembaruan basis data, secara umum itu akan memuat file skrip dan kemudian menjalankannya di server target. Entah Anda harus menambahkan logika untuk memisahkan bets seperti yang dilakukan Studio Manajemen (catatan: penuh dengan bahaya), atau menulis skrip sedemikian rupa sehingga seluruh skrip dapat dieksekusi dengan sukses sebagai bets tunggal.

    Seperti disebutkan dalam jawaban lain, Anda dapat melakukan tes / CREATEmenggunakan metode ini (atau kombinasi lain dari DROP/ CREATE, dll.). Yang saya suka lakukan adalah membuat objek rintisan jika objek tidak ada, dan kemudian gunakan ALTER <object>untuk benar-benar melakukan pembuatan atau perubahan. Pendekatan ini tidak menjatuhkan dependensi, seperti izin atau properti yang diperluas, dan tidak perlu menyalin / menempelkan logika rawan kesalahan untuk melakukan CREATE/ ALTERdalam satu pernyataan.

    Berikut adalah templat yang saya gunakan untuk membuat atau mengubah fungsi skalar. Saya akan meninggalkannya sebagai latihan bagi pembaca untuk mengadaptasinya ke jenis objek lain (procs tersimpan, pemicu, dll.).

IF NOT EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[<schema>].[<function name>]') AND type IN ('FN', 'FS'))
    EXEC sp_executesql N'CREATE FUNCTION [<schema name>].[<function name>] (@a int) RETURNS int AS BEGIN /* Stub */ RETURN @a END'

EXEC sp_executesql N'
ALTER FUNCTION [<schema name>].[<function name>]
/* ... */
'
Jon Seigel
sumber
Bagaimana cara opsi 1 bekerja di sini? Menambahkan huruf GObenar - benar memastikan skrip akan rusak, karena itu tidak IFakan mengarah ke mana pun.
Aaron Bertrand
@ Harun: Saya sedang memikirkan DROP/ CREATEskenario - diedit. Terima kasih.
Jon Seigel
1

Anda memiliki opsi untuk memeriksa apakah objek ada di databasedan membuat jika tidak:

IF OBJECT_ID('new_function', 'FN') IS NULL
BEGIN
  EXEC('CREATE FUNCTION new_function() RETURNS INT AS BEGIN RETURN 1 END');
END;
go

ALTER FUNCTION new_function() RETURNS INT AS
BEGIN

...
Sorack
sumber