SQL सर्वर में एक ही अपवाद को कैसे फिर से फेंकना है


86

मैं एसक्यूएल सर्वर में उसी अपवाद को फिर से उखाड़ फेंकना चाहता हूं जो अभी-अभी मेरे ब्लॉक में हुआ है। मैं एक ही संदेश फेंकने में सक्षम हूं लेकिन मैं एक ही त्रुटि फेंकना चाहता हूं।

BEGIN TRANSACTION
    BEGIN TRY
        INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description)
            VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
        COMMIT TRANSACTION
    END TRY
    
    BEGIN CATCH
        declare @severity int; 
        declare @state int;

        select @severity=error_severity(), @state=error_state();

        RAISERROR(@@Error,@ErrorSeverity,@state);
        ROLLBACK TRANSACTION
    END CATCH

RAISERROR(@@Error, @ErrorSeverity, @state);

यह पंक्ति त्रुटि दिखाएगी, लेकिन मैं ऐसा कुछ कार्यशीलता चाहता हूं। यह त्रुटि संख्या 50000 के साथ त्रुटि उठाती है, लेकिन मैं चाहता हूं कि त्रुटि संख्या को फेंक दिया जाए जो मैं गुजर रहा हूं @@error,

मैं इस त्रुटि को दृश्यपटल पर नहीं पकड़ना चाहता हूं।

अर्थात

catch (SqlException ex)
{
    if ex.number==2627
    MessageBox.show("Duplicate value cannot be inserted");
}

मुझे यह कार्यक्षमता चाहिए। जिसका उपयोग करके प्राप्त नहीं किया जा सकता है raiseerror। मैं अंत में कस्टम त्रुटि संदेश नहीं देना चाहता।

RAISEERROR जब मैं ErrorNo को कैच में फेंकने के लिए पास करूं, तो उल्लेखित त्रुटि के नीचे लौटना चाहिए

Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,

लाइन 14 UNIQUE प्रमुख बाधा 'UK_DomainCode' का उल्लंघन। डुप्लिकेट कुंजी को ऑब्जेक्ट 'Tag.tblDomain' में सम्मिलित नहीं किया जा सकता है। बयान समाप्त कर दिया गया है।

संपादित करें:

यदि मैं चाहता हूं कि यदि मैं चाहता हूं कि जमा प्रक्रिया का उपयोग न करने का दोष क्या हो सकता है, तो संग्रहीत कार्यविधि पर विचार करने वाले अपवाद में कई प्रश्न शामिल हैं जिन्हें निष्पादित करने की आवश्यकता है?

जवाबों:


120

यदि त्रुटि होती है और त्रुटि संदेश की रिपोर्ट करता है, तो बयानों की एक श्रृंखला को रोलबैक करने के लिए पूरी तरह कार्यात्मक स्वच्छ कोड नमूना है।

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    if @@trancount > 0 rollback transaction;
    throw;
end catch

SQL 2012 से पहले

begin try
    begin transaction;
    
    ...
    
    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    if @@trancount > 0 rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch

8
मैं एक संग्रहीत प्रक्रिया के बीच में इसका उपयोग कर रहा था, और पाया कि यह निष्पादित करना जारी रखेगा raiserror, जो कि a के बाद c # बाहर निकलने से अलग है throw। इसलिए मैंने returnअंदर से जोड़ा catchक्योंकि मैं उस व्यवहार से मेल खाना चाहता था।
ब्रायन जे

@BogdanBogdanov मैंने आपका संपादन वापस कर दिया क्योंकि इस कोड का बिंदु कम से कम होना चाहिए और इसके स्थान पर दर्ज किए गए वास्तविक कोड से अलग नहीं होना चाहिए ...
बेन ग्रिपका

ठीक है, कोई बात नहीं, @ ग्रिपका। मैं इसे स्क्रीन पर अधिक पठनीय बनाने की कोशिश करता हूं। रोलबैक करने का कारण बताने के लिए धन्यवाद।
बोगदान बोगदानोव

1
@ ब्रायनज: आम तौर पर, निष्पादन बंद हो जाता है या नहीं, यह मूल त्रुटि की गंभीरता पर निर्भर करता है। यदि गंभीरता> = 11 है, तो निष्पादन बंद हो जाना चाहिए। यह वास्तव में अजीब है, क्योंकि एक गंभीरता के साथ कैच ब्लॉक के अंदर किशमिश> = 11 अब निष्पादन को नहीं रोकता है। आपका अवलोकन बहुत अच्छा है और यह दिखाता है कि ब्रेन-डेड sql सर्वर है, कम से कम 2008r2। नए संस्करण बेहतर लगते हैं।
कोस्टा

1
@ कोस्टा देखें RAISERROR()डॉक्स । Ity11 की गंभीरता केवल एक CATCHब्लॉक में कूदती है अगर यह एक ब्लॉक के अंदर है TRY। तो तुम चाहिए है BEGIN TRY…END CATCHअगर आप अपने चाहते कोड के आसपास RAISERROR()प्रवाह नियंत्रण को प्रभावित करने के लिए।
बिंकी जू २19

137

एसक्यूएल 2012 फेंक वक्तव्य का परिचय देता है:

http://msdn.microsoft.com/en-us/library/ee677615.aspx

यदि THROW कथन को मापदंडों के बिना निर्दिष्ट किया गया है, तो उसे CATCH ब्लॉक के अंदर दिखाई देना चाहिए। इसके कारण पकड़े गए अपवाद को उठाया जाता है।

BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH

2
खबरदार, ऐसा लगता है कि यह समाधान केवल sql सर्वर 2012 और इसके बाद के संस्करण से काम करता है: msdn.microsoft.com/en-us/library/ee677615.aspx
Adi

3
@BogdanBogdanov ताकि आप त्रुटि को लॉग कर सकें, संभवत: कुछ स्थितियों को संभाल सकते हैं, लेकिन यदि आप नहीं कर सकते हैं तो आप त्रुटि को फिर से उखाड़ फेंकना चाहते हैं, इसलिए किसी भी उच्चतर प्रयास / पकड़ को संभालने का मौका मिल सकता है
रॉबर्ट मैककॉन

हां, @ रोबर्ट मैककी। मैं यह पता लगाता हूं। क्षमा करें, यह टिप्पणी साफ़ करना भूल गया।
बोगडान बोगदानोव

3
ROLLBACKलाइन पर वह अर्धविराम महत्वपूर्ण है! इसके बिना आपको ए SQLException: Cannot roll back THROW
idontevenseethecode

5

CATCH ब्लॉक के अंदर रीथ्रोइंग (पूर्व SQL2012 कोड, SQL2012 के लिए THROW स्टेटमेंट का उपयोग करें और बाद में):

DECLARE
    @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
    @ErrorNumber int = ERROR_NUMBER(),
    @ErrorSeverity int = ERROR_SEVERITY(),
    @ErrorState int = ERROR_STATE(),
    @ErrorLine int = ERROR_LINE(),
    @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)

4

मुझे लगता है कि आपकी पसंद हैं:

  • त्रुटि न पकड़ें (इसे बुदबुदाने दें)
  • एक रिवाज उठाएं

कुछ बिंदु पर, SQL शायद एक reraise कमांड, या केवल कुछ त्रुटियों को पकड़ने की क्षमता का परिचय देगा। लेकिन अभी के लिए, वर्कअराउंड का उपयोग करें। माफ़ करना।


7
sql 2012 में आप नए
THROW

5
हाँ। बेशक, यह तब उपलब्ध नहीं था जब यह सवाल पूछा गया था।
रोब फार्ले

एक नई त्रुटि को पकड़ने और फेंकने की तुलना में अधिक महत्वपूर्ण होगा कि इसे पकड़ न लें और इसे 'बबल अप' दें क्योंकि अपवाद को ठीक से संभालने के लिए आपको कुछ साफ-सुथरी, सुधारात्मक कार्रवाई और बंद गतिविधियों की आवश्यकता होगी। एक स्पष्ट उदाहरण एक कर्सर के बंद और निपटान के लिए होगा। अन्य उदाहरण लॉगिंग प्रक्रिया को निष्पादित करने या कुछ डेटा रीसेट करने के लिए हो सकते हैं।
एंटनी बूथ

1

आप नहीं कर सकते हैं: केवल इंजन 50000 से कम त्रुटियों को फेंक सकता है। आप बस इतना कर सकते हैं कि एक अपवाद है जो ऐसा दिखता है ...

कृपया मेरा जवाब यहाँ देखें

प्रश्नकर्ता ने ग्राहक पक्ष के लेन-देन का उपयोग वह करने के लिए किया जो वह चाहता था जो मुझे लगता है कि एक मूक सा है ...


0

ठीक है, यह एक समाधान है ... :-)

DECLARE @Error_Number INT
BEGIN TRANSACTION 
    BEGIN TRY
    INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') 
    /* Column 'Name' has unique constraint on it*/
    END TRY
    BEGIN CATCH

            SELECT ERROR_NUMBER()
            --RAISERROR (@ErrorMessage,@Severity,@State)
            ROLLBACK TRAN
    END CATCH

यदि आप कैच ब्लॉक को नोट करते हैं, तो यह त्रुटि नहीं बढ़ा रहा है, लेकिन वास्तविक त्रुटि संख्या लौटा रहा है (और लेन-देन को भी रोलबैक करेगा)। अब आपके .NET कोड में, अपवाद को पकड़ने के बजाय, यदि आप ExecuteScalar () का उपयोग करते हैं, तो आपको वास्तविक त्रुटि संख्या मिलती है जो आप चाहते हैं और उचित संख्या दिखाते हैं।

int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
    MessageBox.Show("Some message");
}

उम्मीद है की यह मदद करेगा,

संपादित करें: - बस एक नोट, यदि आप प्रभावित रिकॉर्ड की संख्या प्राप्त करना चाहते हैं और ExecuteNonQuery का उपयोग करने की कोशिश कर रहे हैं, तो उपरोक्त समाधान आपके लिए काम नहीं कर सकता है। अन्यथा, मुझे लगता है कि यह आपके लिए जरूरी है। मुझे बताएं।


@ आशीष गुप्ता: मदद के लिए Thx, लेकिन मुझे डेटाबेस से फ्रंटएंड पर फेंकने के लिए अपवाद की आवश्यकता है, अन्यथा मेरे पास प्रिंट एरर_नंबर (), रिटर्न एरर_नंबर जैसे कई विकल्प खुले हैं और 1 यू सुझाव दिया गया है
शांतनु सिंह

0

किसी त्रुटि के बाद संग्रहीत कार्यविधि में निष्पादन को रोकने का तरीका और कॉलिंग प्रोग्राम में त्रुटि को वापस करने के लिए प्रत्येक कथन का पालन करना है जो इस कोड के साथ एक त्रुटि फेंक सकता है:

If @@ERROR > 0
Return

मुझे खुद यह जानकर आश्चर्य हुआ कि एक संग्रहीत कार्यविधि में निष्पादन एक त्रुटि के बाद भी जारी रह सकता है - यह महसूस न करने के कारण बग को ट्रैक करने के लिए कुछ कठिन हो सकता है।

इस प्रकार की त्रुटि हैंडलिंग समानताएं (पूर्व। नेट) विज़ुअल बेसिक 6. SQL सर्वर 2012 में थ्रो कमांड की प्रतीक्षा कर रही है।


0

यह देखते हुए कि आप अभी तक 2012 में स्थानांतरित नहीं हुए हैं, मूल त्रुटि कोड के बबलिंग को लागू करने का एक तरीका यह है कि आप जो अपवाद हैं उसे फिर से पकड़ ब्लॉक से फेंक रहे अपवाद के पाठ संदेश भाग का उपयोग करें। याद रखें कि इसमें कुछ संरचना हो सकती है, उदाहरण के लिए, आपके कॉलर कोड के लिए XML टेक्स्ट इसके कैच ब्लॉक में पार्स करने के लिए।


0

जब आप लेन-देन के भीतर SQL स्टेटमेंट को निष्पादित करना चाहते हैं और अपने कोड में त्रुटि को फीड कर सकते हैं, तो आप उन परिदृश्यों के लिए एक आवरण संग्रहित प्रक्रिया भी बना सकते हैं।

CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
    @SQL nvarchar(max)
)
AS

SET NOCOUNT ON

BEGIN TRY
    BEGIN TRANSACTION
        EXEC(@SQL)
    COMMIT TRANSACTION
END TRY

BEGIN CATCH
    DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
    SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
    ROLLBACK TRANSACTION
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH

GO

-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'

-2

डिजाइन के दृष्टिकोण से, मूल त्रुटि संख्या और कस्टम संदेशों के साथ अपवादों को फेंकने का क्या मतलब है? कुछ हद तक यह अनुप्रयोगों और डेटाबेस के बीच इंटरफ़ेस अनुबंध को तोड़ता है। यदि आप मूल त्रुटियों को पकड़ना चाहते हैं और उन्हें उच्च कोड में संभालना चाहते हैं, तो उन्हें डेटाबेस में न संभालें। फिर जब आप एक अपवाद को पकड़ते हैं, तो आप उपयोगकर्ता को प्रस्तुत संदेश को अपनी इच्छानुसार बदल सकते हैं। मैं इसे हालांकि नहीं करूंगा, क्योंकि यह आपके डेटाबेस कोड hmm को 'सही नहीं' बनाता है। जैसा कि दूसरों ने कहा है कि आपको अपने स्वयं के त्रुटि कोड (50000 से ऊपर) के एक सेट को परिभाषित करना चाहिए और इसके बजाय उन्हें फेंक देना चाहिए। तब आप संभावित व्यावसायिक मुद्दों से अलग-अलग अखंडता के मुद्दों ('डुप्लिकेट मानों की अनुमति नहीं है) को अलग कर सकते हैं -' ज़िप कोड अमान्य है ',' कोई पंक्तियाँ मापदंड से मेल खाते नहीं पाए गए 'और इसी तरह।


9
मूल त्रुटि संख्याओं और कस्टम संदेशों के साथ अपवादों को फेंकने का क्या मतलब है? मान लें कि आप एक या दो विशिष्ट (अपेक्षित) त्रुटियों को सीधे पकड़ ब्लॉक में संभालना चाहते हैं और बाकी को उच्चतर परतों के लिए छोड़ देते हैं। इस प्रकार आपको उन अपवादों को फिर से उखाड़ फेंकने में सक्षम होने की आवश्यकता है जिन्हें आपने नहीं किया था ... अधिमानतः रिपोर्टिंग का सहारा लेने और त्रुटियों को किसी अन्य, विशेष तरीके से संभालने के बिना।
जेन्डे

1
@ जेन्डा ने जो बताया, उसके अलावा, मैं यह सुनिश्चित करने के लिए कि कैद का निष्पादन जारी नहीं है, बहुत कुछ C # में करना पसंद है try { code(); } catch (Exception exc) { log(exc); throw; } finally { cleanup(); }, जहां throw;मूल अपवाद को इसके मूल संदर्भ के साथ उठाया जाएगा।
आर। श्रेयर्स

मैं त्रुटियों को पकड़ता हूं और SQL में कस्टम एरर मैसेजेस को फिर से विवरण में जोड़ने के लिए कहता हूं कि कौन सी लाइन में त्रुटि हुई या अन्य विवरण (जैसे कि डालने की कोशिश कर रहा डेटा) मुझे त्रुटि को ट्रैक करने में मदद करने के लिए।
रसेल हैंकिंस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.