TSQL - एक BEGIN .. END ब्लॉक के अंदर GO का उपयोग कैसे करें?


96

मैं कई डेवलपमेंट डेटाबेस से स्टेजिंग / प्रोडक्शन में स्वचालित रूप से परिवर्तन के लिए एक स्क्रिप्ट उत्पन्न कर रहा हूँ। मूल रूप से, यह परिवर्तन-लिपियों का एक समूह लेता है, और उन्हें एक स्क्रिप्ट में विलय करता है, प्रत्येक स्क्रिप्ट को एक IF whatever BEGIN ... ENDबयान में लपेटता है ।

हालाँकि, कुछ लिपियों के लिए एक GOकथन की आवश्यकता होती है, उदाहरण के लिए, SQL पार्सर के बनने के बाद एक नए कॉलम के बारे में जानता है।

ALTER TABLE dbo.EMPLOYEE 
ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO -- Necessary, or next line will generate "Unknown column:  EMP_IS_ADMIN"
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever

हालांकि, एक बार मैं इसे एक IFब्लॉक में लपेटता हूं :

IF whatever
BEGIN
    ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
    GO
    UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
END

यह विफल रहता है क्योंकि मैं BEGINबिना मेल के साथ भेज रहा हूं END। हालाँकि, यदि मैं GOइसे हटाता हूँ तो यह एक अज्ञात कॉलम के बारे में फिर से शिकायत करता है।

क्या एक ही IFब्लॉक के भीतर एक ही कॉलम बनाने और अपडेट करने का कोई तरीका है ?


2
देखें stackoverflow.com/questions/4855537/… कृपया
gbn

2
@ जीबी: हां, मुझे एहसास है कि ऐसा क्यों होता है (दूसरा पैराग्राफ देखें) ; लेकिन मुझे नहीं पता कि इसके चारों ओर कैसे काम किया जाए - क्या मुझे वाकई हर क्वेरी को स्ट्रिंग्स के एक गुच्छा में बदलने की जरूरत है !?
ब्लूराजा - डैनी पफ्लुगुफ्ट

@ ब्ल्यूराज: क्या चिंता है? यदि यह काम करता है, तो यह सब दिन के अंत में मायने रखता है। यदि उपलब्ध समाधान के साथ कोई वैध व्यावसायिक समस्या है, तो कृपया व्यक्त करें। वहाँ कुछ विशेष रूप से तार के एक समूह में हर क्वेरी परिवर्तित करने के बारे में डिस्कनेक्ट है?
मेलमोकब

1
@ मेलमोकब: हाँ, एक समस्या है; यदि शब्द GO का उपयोग किसी अन्य संदर्भ में किया जाता है (जैसे कि एक टिप्पणी, या एक स्ट्रिंग), तो स्क्रिप्ट काम नहीं करेगी। साथ ही, हम कुछ भी गलत होने पर त्रुटि संदेशों में उपयोगी लाइन-नंबर खो देते हैं। क्या लेनदेन के साथ ऐसा करने का कोई तरीका नहीं है? या कोशिश / पकड़?
ब्लूराजा - डैनी Pflughoeft

@BlueRaja: 1) मेरा मानना GOहै कि अपने आप एक लाइन में होना चाहिए, इसलिए आप केवल उस मामले को खोज सकते हैं, और शब्द के प्रत्येक उदाहरण को नहीं GO। 2) आप हमेशा लॉग कर सकते हैं कि कौन से कथन सफलतापूर्वक पूर्ण हुए। या आप पूरी चीज़ को एक कोशिश / कैच में लपेट सकते हैं और कुछ लाइन का उपयोग करके अपने स्वयं के लाइन नंबरों का उपयोग कर सकते हैं, जैसे @lineNo, जिसे आप ट्रैक करते हैं, और त्रुटि पर रिपोर्ट करते हैं। चूंकि आप ये स्वचालित रूप से उत्पन्न कर रहे हैं, इसलिए इस तरह के बदलाव करना एक हवा होना चाहिए। ऐसा लगता है कि जैसे आपको लगता है कि आप इस मार्ग का पता नहीं लगाना चाहते हैं, जब मुझे लगता है कि आपकी सभी चिंताओं के लिए समाधान ढूंढे जाने हैं।
मेलमोकब

जवाबों:


44

मुझे भी यही समस्या थी और आखिरकार SET NOEXEC का उपयोग कर इसे हल करने में कामयाब रहे ।

IF not whatever
BEGIN
    SET NOEXEC ON; 
END

ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever

SET NOEXEC OFF; 

2
यह एक महान उपाय है!
Bazinga

+1! यह SS मोड स्क्रिप्ट (यानी एक मास्टर परिनियोजन स्क्रिप्ट) में उपयोग के लिए अब तक का एकमात्र व्यावहारिक उत्तर है SQLCMDजो कॉल करता है ( :rआदेश के माध्यम से ) अन्य SS लिपियों (यानी उप-परिनियोजन स्क्रिप्ट) को उन कॉलों में से कुछ के साथ ifबताता है। Oded's, mellamokb's और एंडी जॉइनर के कॉल्स / - के सभी स्टेटमेंट्स को घेरने के उत्तर गैर-शुरुआत वाले हैं। इसके अलावा, - विधि तब तक काम नहीं करेगी जब कोई स्टेटमेंट हो (जैसे इसके लिए एक स्पष्ट पूर्व की आवश्यकता होती है)। लेकिन, आदमी, "पवित्र डबल नकारात्मक, बैटमैन!" ;)execbeginendbeginendcreatego
टॉम

पठनीयता के लिए (उदाहरण के लिए, डबल-निगेटिव को दूर करने में मदद करने के लिए और यह स्पष्ट करना कि यह एक वर्चुअल if -ब्लॉक का अनुकरण कर रहा है), मैं एक -- If whateverटिप्पणी के साथ ब्लॉक को उपसर्ग करूंगा, ब्लॉक को इंडेंट करूंगा और एक --end If whateverटिप्पणी के साथ ब्लॉक को पोस्टफिक्स करूंगा ।
टॉम

तुमने मेरी बेकन बचा ली! मैं मर्ज स्टेटमेंट्स चला रहा था और उन गूंगा गो को एक IF BEGIN END ELSE के अंदर रहना पसंद नहीं है
Omzig

हम्म, मैं किसी भी तरह अद्यतन पर एक त्रुटि हो रही है के बाद सेट noexec निष्पादित किया गया है? (त्रुटि है कि अद्यतन करने के लिए स्तंभ नाम अमान्य है) क्वेरी संपादक में MSSQL 2014 पर चल रहा है। ठीक काम करता है अगर हालत झूठी हो जाती है (इस प्रकार noexec बंद रहता है)
जैरी

43

GO SQL नहीं है - यह कुछ MS SQL टूल्स में प्रयुक्त बैच विभाजक मात्र है।

यदि आप इसका उपयोग नहीं करते हैं, तो आपको यह सुनिश्चित करने की आवश्यकता है कि बयान अलग-अलग निष्पादित किए जाएं - या तो अलग-अलग बैचों में या आबादी के लिए गतिशील एसक्यूएल का उपयोग करके (धन्यवाद @ जीबीएन):

IF whatever
BEGIN
    ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL;

    EXEC ('UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever')
END

8
हां मैं समझता हूं। यह प्रश्न का उत्तर नहीं देता है - मुझे उसी IFब्लॉक में एक कॉलम बनाने और अपडेट करने की आवश्यकता है ।
ब्लूराजा - डैनी पफ्लुगुफ्ट

@Oded: ;यहाँ मदद मिलेगी? - आपने अभी अपना उत्तर संपादित किया है: ओ)
नील नाइट

@ नील - यह मेरी सोच है, हाँ।
उल्लू

;या तो काम नहीं करता है - पार्सर अभी भी मुझे "EMP_IS_ADMIN" अमान्य कॉलम नाम
ब्लूराजा - डैनी पफ्लुगुएफ्ट

जब बैच संकलित किया जाता है, तो EMP_IS_ADMIN मौजूद नहीं होता है। stackoverflow.com/questions/4855537/…
gbn

16

आप sp_executesqlप्रत्येक GOकथन के बीच की सामग्री को अलग-अलग स्ट्रिंग में विभाजित करने की कोशिश कर सकते हैं , जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है। इसके अलावा, एक @statementNo वेरिएबल है जिसे ट्रैक करने के लिए स्टेटमेंट को आसान डीबगिंग के लिए निष्पादित किया जा रहा है जहां एक अपवाद हुआ। पंक्ति संख्या उस प्रासंगिक कथन संख्या की शुरुआत के सापेक्ष होगी जो त्रुटि का कारण बनी।

BEGIN TRAN

DECLARE @statementNo INT
BEGIN TRY
    IF 1=1
    BEGIN
        SET @statementNo = 1
        EXEC sp_executesql
            N'  ALTER TABLE dbo.EMPLOYEE
                    ADD COLUMN EMP_IS_ADMIN BIT NOT NULL'

        SET @statementNo = 2
        EXEC sp_executesql
            N'  UPDATE dbo.EMPLOYEE
                    SET EMP_IS_ADMIN = 1'

        SET @statementNo = 3
        EXEC sp_executesql
            N'  UPDATE dbo.EMPLOYEE
                    SET EMP_IS_ADMIN = 1x'
    END
END TRY
BEGIN CATCH
    PRINT 'Error occurred on line ' + cast(ERROR_LINE() as varchar(10)) 
       + ' of ' + 'statement # ' + cast(@statementNo as varchar(10)) 
       + ': ' + ERROR_MESSAGE()
    -- error occurred, so rollback the transaction
    ROLLBACK
END CATCH
-- if we were successful, we should still have a transaction, so commit it
IF @@TRANCOUNT > 0
    COMMIT

आप आसानी से बहु-पंक्ति कथनों को निष्पादित कर सकते हैं, जैसा कि ऊपर दिए गए उदाहरण में दिखाया गया है, बस उन्हें एकल उद्धरण ( ') में लपेटकर । ''स्क्रिप्ट्स बनाते समय एक सिंगल सिंगल-कोट ( ) के साथ स्ट्रिंग के अंदर निहित किसी भी एक उद्धरण से बचना न भूलें ।


नहीं लगता है कि यह कई लाइनों में विभाजित आदेशों के लिए काम करेगा, यह होगा?
ब्लूराजा - डैनी Pflughoeft

@BlueRaja: मैंने उदाहरण दिखाया है कि यह कैसे काम करेगा। वे तार मल्टी-लाइन हो सकते हैं, जब तक कि अंदर मौजूद कोई भी एकल उद्धरण (') डबल-सिंगल कोट (' ') का उपयोग करके बच जाता है
mellamokb

1
@ ममलोक: सख्ती से बोलना, केवल अद्यतन की जरूरत है sp_executesql ... stackoverflow.com/questions/4855537/…
gbn

1
@ पेट: सच। लेकिन अगर आप इसे 100 के बयानों के लिए स्वचालित करने जा रहे हैं, तो यह आसान होगा कि आप इसे कब और कहां तय करें, इसके बजाय सभी बयानों पर आंख मूंद कर इसे लागू करें।
मेलमोकब

@ जीबी @ ममलोकब: मेरा मतलब था जैसे बयान SELECT * <newline> FROM whatever। अगर मैं हर लाइन को अपने EXEC स्टेटमेंट के साथ निष्पादित करता हूं, तो यह टूट जाएगा। या आप यह सुझाव दे रहे हैं कि मैं हर GOबयान पर विराम लगाऊं?
ब्लूराजा - डैनी पफ्लुगुफ्ट

9

मुझे अंततः GOइसकी अपनी लाइन के हर उदाहरण को बदलकर काम करने को मिला

END
GO

---Automatic replacement of GO keyword, need to recheck IF conditional:
IF whatever
BEGIN

यह एक स्ट्रिंग में बयानों के प्रत्येक समूह को लपेटने के लिए बहुत बेहतर है, लेकिन अभी भी आदर्श से बहुत दूर है। यदि कोई बेहतर समाधान पाता है, तो उसे पोस्ट करें और मैं इसके बजाय इसे स्वीकार करूंगा।


6
यदि पहली शर्त "अगर यह कॉलम मौजूद नहीं है", तो ब्लॉक का पहला स्टेटमेंट "इस कॉलम को जोड़ें" है, तो सशर्त की दूसरी जांच कॉलम को ढूंढ लेगी और दूसरे स्टेटमेंट को निष्पादित नहीं
करेगी

@ डैमियन: सच; सौभाग्य से, मेरे मामले में ऐसा कभी नहीं होगा (सशर्त हमेशा एक विशिष्ट तालिका में एक विशिष्ट मूल्य के लिए एक जांच है, जिसे हमेशा IFब्लॉक के अंतिम विवरण के रूप में जोड़ा जाता है )। ऐसा लगता है जैसे SQL में ऐसा करने का कोई अच्छा तरीका नहीं है।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

मीना जैकब का set noexecउत्तर एसएस मोड स्क्रिप्ट (यानी एक मास्टर तैनाती स्क्रिप्ट) में उपयोग के लिए अब तक का एकमात्र व्यावहारिक उत्तर है SQLCMDजो कॉल करता है ( :rकमांड के माध्यम से ) अन्य एसएस लिपियों (यानी उप-तैनाती लिपियों) के अंदर उन कॉलों में से कुछ के साथ ifविवरण। Oded's, mellamokb's और Andy Joiner's के सभी स्टेटमेंट को execकॉल / begin- में संलग्न करने के उत्तर endगैर-शुरुआत वाले हैं। इसके अलावा, begin- endविधि तब तक काम नहीं करेगी जब कोई createस्टेटमेंट हो (जैसे इसके लिए एक स्पष्ट goपूर्व की आवश्यकता होती है)।
टॉम

8

आप GO inbetween के बजाय BEGIN और END में कथनों को संलग्न कर सकते हैं

IF COL_LENGTH('Employees','EMP_IS_ADMIN') IS NULL --Column does not exist
BEGIN
    BEGIN
        ALTER TABLE dbo.Employees ADD EMP_IS_ADMIN BIT
    END

    BEGIN
        UPDATE EMPLOYEES SET EMP_IS_ADMIN = 0
    END
END

(नॉर्थविंड डेटाबेस पर परीक्षण किया गया)

संपादित करें: (शायद SQL2012 पर परीक्षण किया गया)


1
कृपया कारण -1
एंडी जॉइनर

1
पता नहीं क्यों इसे नीचा दिखाया गया था ... मेरे लिए एक आकर्षण की तरह काम करता है।
थोरिन

10
SQL Server 2008 R2 का उपयोग करना, यह मेरे लिए काम नहीं करता है, फिर भी मुझे एक त्रुटि 'अवैध कॉलम नाम' EMP_IS_ADMIN 'मिलता है।' UPDATE लाइन पर।
मर्कोवा

BEGIN-END बैचिंग ने SQL Server 2016 का उपयोग करके मेरे लिए काम किया। IMO यह सबसे साफ वाक्यविन्यास है।
उबेर श्नकोज़

मीना जैकब का set noexecउत्तर एसएस मोड स्क्रिप्ट (यानी एक मास्टर तैनाती स्क्रिप्ट) में उपयोग के लिए अब तक का एकमात्र व्यावहारिक उत्तर है SQLCMDजो कॉल करता है ( :rकमांड के माध्यम से ) अन्य एसएस लिपियों (यानी उप-तैनाती लिपियों) के अंदर उन कॉलों में से कुछ के साथ ifविवरण। Oded's, mellamokb's और Andy Joiner's के सभी स्टेटमेंट को execकॉल / begin- में संलग्न करने के उत्तर endगैर-शुरुआत वाले हैं। इसके अलावा, begin- endविधि तब तक काम नहीं करेगी जब कोई createस्टेटमेंट हो (जैसे इसके लिए एक स्पष्ट goपूर्व की आवश्यकता है)।
टॉम

1

आप इस समाधान की कोशिश कर सकते हैं:

if exists(
SELECT...
)
BEGIN
PRINT 'NOT RUN'
RETURN
END

--if upper code not true

ALTER...
GO
UPDATE...
GO

1
बहुत उपयोगी नहीं है अगर आपके पास कई हैं-दूसरे एक के बाद एक ब्लॉक करते हैं, है ना?
जेरी

0

मैंने इसके RAISERRORलिए अतीत में उपयोग किया है

IF NOT whatever BEGIN
    RAISERROR('YOU''RE ALL SET, and sorry for the error!', 20, -1) WITH LOG
END

ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever

-1

आप कोड को छोड़ने के लिए एक GOTOऔर LABELकथनों को शामिल कर सकते हैं , इस प्रकार GOखोजशब्दों को बरकरार रख सकते हैं ।


5
ऐसा लगता है कि जब वे SQL में भेजे गए बैच में नहीं हैं, तो GOEL के बयानों में LABEL को संदर्भित नहीं किया जा सकता है
berkeleybross
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.