Mevcut değilse, koda göre yeni işlev oluşturma


15

Veritabanımdaki komut dosyasıyla yeni işlev oluşturmak istiyorum. Komut dosyası kodu aşağıdadır:

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

Ancak yukarıdaki komut dosyasını yürüttüğümde, SQL Server bir hata döndürür:

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

Yanıtlar:


16

Ocak 2017 Güncellemesi - SQL Server 2016+ / Azure SQL Veritabanı

SQL Server 2016 ve Azure SQL Veritabanı'nın geçerli sürümü artık işlevler, yordamlar, tablolar, veritabanları vb. İçin aşağıdaki sözdizimine sahiptir DROP IF EXISTS:

DROP FUNCTION IF EXISTS dbo.fn_myfunc;

SQL Server 2016 Service Pack 1, modüller (işlevler, prosedürler, tetikleyiciler, görünümler) için daha da iyi işlevsellik ekler; bu da izinlerin veya bağımlılıkların kaybolması anlamına gelmez ( CREATE OR ALTER):

CREATE OR ALTER FUNCTION dbo.fn_myfunc ...

Bu sözdizimi geliştirmelerinin her ikisi de kaynak kontrolü, dağıtımlar vb. İçin kullanılan çok daha basit komut dosyalarına yol açabilir.

Ama eğer kullanıyorsanız ...


eski versiyonlar

Management Studio'dan komut dosyası yazarken SQL Server'ın yapması gerekenler:

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

Veya şöyle diyebilirsiniz:

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

Veya sadece şunu söyleyebilirsiniz:

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

(Burada işlev zaten mevcut değilse bir hata mesajı alırsınız, ancak komut dosyası bir sonraki GO'dan devam eder, bu nedenle bırakma işe yarayıp çalışmadığına göre, işlev yine de (yeniden) oluşturulur.)

İşlevi bırakıp yeniden oluşturursanız, izinleri ve potansiyel olarak bağımlılık bilgilerini de kaybedeceğinizi unutmayın.


1
yani hiçbir anahtar kelime $$ CREATE OR REPLACE $$? yazık.
Haziran'da

@zinking hayır, ama belki gelecekteki bir sürümde. Lütfen oylayın / yorum yapın: connect.microsoft.com/SQLServer/feedback/details/127219/…
Aaron Bertrand

1
@AaronBertrand Oy vermek için iyi bir fikir, ancak bağlantı koptu
mavimsi

@ Maalesef evet, bağlantıyı gönderdiğimde üç yıl önce öğeyi kaldırdılar ve şimdi ... connect.microsoft.com/SQLServer/feedback/details/344991/… veya connect.microsoft.com/SQLServer/feedback adresini
Aaron Bertrand


1

Hata oldukça açıklayıcı. Bunu düzeltmenin birkaç yolu vardır.

  1. GOSözde anahtar kelimeyi ve DROP/ CREATEnesneyi kullanarak komut dosyasını Management Studio'daki farklı gruplara ayırın . (Anahtar kelimenin kendisini Management Studio seçeneklerinde değiştirilebileceğini unutmayın, ancak bu de facto ayarıdır, bu yüzden onu yalnız bırakmanızı öneririm).

    Bir komut dosyası (veya bir komut dosyasının seçilen bölümü) çalıştırdığınızda, Management Studio her komut dosyası parçasını GOs arasında ayırır ve parçaları ayrı ayrı SQL Server'a sıralı olarak gönderir.

  2. Başka bir toplu iş içinden ayrı bir toplu iş göndermek için dinamik SQL kullanın.

    Bu tercih edilen yöntemdir, çünkü komut dosyanız doğru bir şekilde yürütmek için harici işlevselliğe bağlı değildir. Örneğin, uygulamanızda bir veritabanı güncelleme programı varsa, genel olarak konuşursak bir komut dosyası yükler ve daha sonra hedef sunucuda yürütür. Grupları Management Studio'nun yaptığı gibi ayırmak için mantık eklemeniz gerekir (not: tehlikeyle dolu) veya komut dosyasını tüm komut dosyasının başarıyla tek bir toplu iş olarak yürütülebileceği şekilde yazmanız gerekir.

    Başka bir cevapta belirtildiği gibi, bir test / CREATEbu yöntemi kullanarak (veya DROP/ CREATE, vb. Gibi başka bir kombinasyon ) yapabilirsiniz. Yapmayı tercih ettiğim şey, nesne yoksa bir saplama nesnesi oluşturmak ve daha sonra ALTER <object>oluşturma veya değişiklik yapmak için kullanın . Bu yaklaşım, izinler veya genişletilmiş özellikler gibi bağımlılıkları düşürmez ve CREATE/ ALTERifadesini tek bir ifadede yapmak için hataya eğilimli mantığı kopyalamak / yapıştırmak gerekmez .

    İşte bir skaler fonksiyon oluşturmak veya değiştirmek için kullandığım şablon. Okuyucunun bunu diğer nesne türlerine (depolanmış procs, tetikleyiciler vb.) Uyarlaması için bir egzersiz olarak bırakacağım.

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>]
/* ... */
'

Seçenek 1 burada nasıl çalışabilir? GOAslında eklemek komut dosyasının bozulmasını sağlar, çünkü IFirade hiçbir yere varamaz.
Aaron Bertrand

@Aaron: Düzenlenen DROP/ CREATEsenaryosunu düşünüyordum . Teşekkürler.
Jon Seigel

1

Nesnenin içinde olup olmadığını kontrol etme databaseve yoksa oluşturma seçeneğiniz vardır :

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

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