यदि यह मौजूद नहीं है तो कोड द्वारा नया फ़ंक्शन बनाएं


15

मैं अपने डेटाबेस में स्क्रिप्ट द्वारा नया कार्य बनाना चाहता हूं। स्क्रिप्ट कोड नीचे है:

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

लेकिन जब मैं उपरोक्त स्क्रिप्ट निष्पादित करता हूं, तो SQL सर्वर एक त्रुटि देता है:

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

जवाबों:


16

अद्यतन जनवरी 2017 - SQL सर्वर 2016+ / Azure SQL डेटाबेस

SQL सर्वर 2016 और Azure SQL डेटाबेस के वर्तमान संस्करण में अब फ़ंक्शन, प्रक्रिया, टेबल, डेटाबेस, आदि के लिए निम्नलिखित सिंटैक्स है DROP IF EXISTS: ( ):

DROP FUNCTION IF EXISTS dbo.fn_myfunc;

और SQL सर्वर 2016 सर्विस पैक 1 मॉड्यूल (फ़ंक्शन, प्रक्रिया, ट्रिगर, विचार) के लिए और भी बेहतर कार्यक्षमता जोड़ता है जिसका अर्थ है अनुमतियों या निर्भरताओं का कोई नुकसान नहीं ( CREATE OR ALTER):

CREATE OR ALTER FUNCTION dbo.fn_myfunc ...

इन दोनों सिंटैक्स एन्हांसमेंट से स्रोत नियंत्रण, परिनियोजन, आदि के लिए उपयोग की जाने वाली बहुत सरल स्क्रिप्ट हो सकती हैं।

लेकिन, यदि आप उपयोग कर रहे हैं ...


पुराने संस्करण

जब आपको प्रबंधन स्टूडियो से यह स्क्रिप्ट आती है तो आपको SQL सर्वर क्या करता है:

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

या आप कह सकते हैं:

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

या आप बस कह सकते हैं:

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

(यहां आपको एक त्रुटि संदेश मिलेगा यदि फ़ंक्शन पहले से मौजूद नहीं है, लेकिन स्क्रिप्ट अगले GO से जारी रहेगी, इसलिए ड्रॉप काम किया या नहीं, फ़ंक्शन अभी भी बनाया जाएगा (पुनः)।)

ध्यान दें कि यदि आप फ़ंक्शन को छोड़ते हैं और इसे फिर से बनाते हैं, तो आप अनुमतियाँ और संभावित निर्भरता जानकारी भी खो देंगे।


1
इसलिए कोई $ $ नहीं है या $ $ सृजन नहीं है? अफ़सोस की बात है।
2

@zink नहीं, लेकिन शायद भविष्य के संस्करण में। कृपया वोट / टिप्पणी: connect.microsoft.com/SQLServer/feedback/details/127219/...
हारून बर्ट्रेंड

1
@AaronBertrand इसके लिए वोट करने के लिए अच्छा विचार है, लेकिन लिंक टूट गया है
नीले रंग

हाँ @bluish खेद है, वे पहले जब मैं लिंक पोस्ट तीन साल के बीच आइटम कुछ समय निकाल दिया है और अब ... प्रयास करें connect.microsoft.com/SQLServer/feedback/details/344991/... या connect.microsoft.com/SQLServer/feedback / विवरण / 351,217 / ...
हारून बर्ट्रेंड

यह अब उपलब्ध हो सकता है: blogs.msdn.microsoft.com/sqlserverstorageengine/2016/11/17/…
Bruno

1

त्रुटि बहुत ही आत्म-व्याख्यात्मक है। इसे ठीक करने के कुछ तरीके हैं।

  1. GOछद्म-कुंजीशब्द, और DROP/ CREATEवस्तु का उपयोग करके प्रबंधन स्टूडियो में स्क्रिप्ट को अलग-अलग बैचों में अलग करें ।(ध्यान दें कि कीवर्ड को प्रबंधन स्टूडियो विकल्पों में ही बदला जा सकता है, लेकिन यह वास्तविक सेटिंग है, इसलिए मेरा सुझाव है कि इसे अकेला छोड़ दें)।

    जब आप स्क्रिप्ट (या स्क्रिप्ट का चयनित भाग) चलाते हैं, तो प्रबंधन स्टूडियो GOs के बीच स्क्रिप्ट के प्रत्येक भाग को अलग करता है , और क्रमिक रूप से अलग-अलग बैचों के रूप में भागों को SQL सर्वर पर भेजता है।

  2. दूसरे बैच के भीतर से एक अलग बैच भेजने के लिए गतिशील SQL का उपयोग करें।

    यह पसंदीदा तरीका है, क्योंकि तब आपकी स्क्रिप्ट सही ढंग से निष्पादित करने के लिए बाहरी कार्यक्षमता पर निर्भर नहीं करती है। उदाहरण के लिए, यदि आपके एप्लिकेशन में डेटाबेस अपडेट प्रोग्राम है, तो सामान्यतया यह एक स्क्रिप्ट फ़ाइल को लोड करेगा और फिर इसे लक्ष्य सर्वर पर निष्पादित करेगा। या तो आपको बैचों को अलग करने के लिए तर्क जोड़ना होगा जैसा कि प्रबंधन स्टूडियो करता है (ध्यान दें: जोखिम से भरा), या स्क्रिप्ट को इस तरह से लिखें कि पूरी स्क्रिप्ट को एक एकल बैच के रूप में सफलतापूर्वक निष्पादित किया जा सके।

    के रूप में एक और उत्तर में उल्लेख किया है, तो आप / एक परीक्षण कर सकते हैं CREATEइस विधि (या के कुछ अन्य संयोजन का उपयोग कर DROP/ CREATE, आदि)। यदि मैं करना पसंद करता हूं तो एक स्टब ऑब्जेक्ट बनाता है यदि ऑब्जेक्ट मौजूद नहीं है, और फिर ALTER <object>वास्तव में निर्माण या परिवर्तन करने के लिए उपयोग करें। यह दृष्टिकोण निर्भरता, जैसे अनुमतियाँ या विस्तारित गुणों को नहीं छोड़ता है, और किसी एकल कथन में CREATE/ के लिए त्रुटि-प्रवण तर्क को कॉपी / पेस्ट करना आवश्यक नहीं है ALTER

    यहाँ वह टेम्प्लेट है जिसका उपयोग मैं स्केलर फ़ंक्शन बनाने या बदलने के लिए करता हूँ। मैं इसे अन्य प्रकार की वस्तुओं (संग्रहीत procs, ट्रिगर्स, आदि) के लिए अनुकूलित करने के लिए पाठक के लिए एक अभ्यास के रूप में छोड़ दूँगा।

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

विकल्प 1 यहाँ कैसे काम कर सकता है? GOवास्तव में जोड़ना यह सुनिश्चित करता है कि स्क्रिप्ट टूट जाएगी, क्योंकि अब IFकहीं नहीं जाएगी।
हारून बर्ट्रेंड

@ एरॉन: मैं DROP/ CREATEपरिदृश्य के बारे में सोच रहा था - संपादित। धन्यवाद।
जॉन सीगेल

1

आपके पास यह जाँचने का विकल्प है कि क्या वस्तु मौजूद है databaseऔर नहीं तो:

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

...
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.