Πώς μπορείτε να ανακτήσετε τιμές σε αποθηκευμένες διαδικασίες του SQL Server με το ADO


Για μια έκδοση αυτού του άρθρου που αφορά τη Microsoft Visual Basic .NET, ανατρέξτε στο θέμα 308049 .

Σύνοψη


Υπάρχουν σημαντικά προβλήματα που πρέπει να λάβετε υπόψη όταν επιχειρείτε να ανακτήσετε τιμές RAISERROR/PRINT/RETURN από τις αποθηκευμένες διαδικασίες του SQL Server μέσω αντικειμένων δεδομένων ActiveX (ADO). Ακολουθούν τρία θέματα:
  • Οι προτάσεις RAISERROR στον SQL Server πρέπει να είναι επίπεδο σοβαρότητας 11-18.
  • Οι προτάσεις ΕΚΤΎΠΩΣΗς στον SQL Server μπορούν επίσης να συμπληρώσουν τη συλλογή σφαλμάτων του ADO. Ωστόσο, οι προτάσεις ΕΚΤΎΠΩΣΗς είναι το επίπεδο σοβαρότητας μηδέν (0) έτσι, τουλάχιστον μία δήλωση RAISERROR απαιτείται στην αποθηκευμένη διαδικασία για την ανάκτηση μιας δήλωσης ΕΚΤΎΠΩΣΗς με το ADO μέσω της συλλογής Errors.
  • Οι τιμές ΕΠΙΣΤΡΟΦΉς σε μια αποθηκευμένη διαδικασία πρέπει να συσχετιστούν με τουλάχιστον μία resultset.

Περισσότερες πληροφορίες


Το παρακάτω δείγμα κώδικα παρουσιάζει την περιήγηση στη συλλογή σφαλμάτων του ADO για να αποκτήσετε πρόσβαση στις λεπτομέρειες RAISERROR/PRINT/RETURN από μια αποθηκευμένη διαδικασία SQL Server που επιστρέφει πολλά συνόλων:
  1. Επικολλήστε και εκτελέστε τον παρακάτω κώδικα στο παράθυρο ISQL_W για να δημιουργήσετε την αποθηκευμένη διαδικασία που χρησιμοποιείται για το δείγμα ADO στο βήμα 4:
          use pubs      GO      if exists (select * from sysobjects where id =        object_id('dbo.ADOTestRPE') and sysstat & 0xf = 4)      drop procedure dbo.ADOTestRPE      GO      create procedure ADOTestRPE      (      @SetRtn  INT=0 OUTPUT,      @R1Num   INT=1,      @P1Num   INT=1,      @E1Num   INT=1,      @R2Num   INT=2,      @P2Num   INT=2,      @E2Num   INT=2      )      AS      DECLARE @iLoop     INT      DECLARE @PrintText VARCHAR(255)      DECLARE @iErrNum   INT      /*   Check for no Resultsets - needed to get the RETURN value back */       IF @R1Num + @R2Num = 0 SELECT NULL      /*   Resultset 1  ******************************* */       IF @R1Num > 0      BEGIN         SET ROWCOUNT @R1Num         SELECT 'Resultset 1' RsNum, Title         FROM Pubs..Titles         SET ROWCOUNT 0      END         /* Must raise a default error context in which to return the PRINT */         /*  statement */        /* (if none present) since PRINT statements are a severity level of */       /*0. */       IF (@P1Num > 0) AND (@E1Num = 0) RAISERROR ("RAISERROR.PError1",         11, 2)      IF @P1Num > 0      BEGIN         SELECT @iLoop = 0         WHILE @iLoop < @P1Num         BEGIN            SELECT @iLoop = @iLoop + 1            SELECT @PrintText = 'PRINT.Resultset.1: Line ' +      CONVERT(char(2), @iLoop)         PRINT @PrintText        END      END      IF @E1Num > 0      BEGIN         SELECT @iLoop = 0         WHILE @iLoop < @E1Num         BEGIN            SELECT @iLoop = @iLoop + 1            SELECT @iErrNum = @iLoop + 201000            RAISERROR ("RAISERROR.Resultset.1", 11, 2)         END      END      /*   Resultset 2  ******************************* */       IF @R2Num > 0      BEGIN         SET ROWCOUNT @R2Num         SELECT 'Resultset 2' RsNum, Title         FROM Pubs..Titles         SET ROWCOUNT 0      END      /* Must raise a default error context in which to return the PRINT */       /*  statement */       /* (if none present) since PRINT statements are a severity level of */       /*  0. */       IF (@P2Num > 0) AND (@E2Num = 0) RAISERROR ("RAISERROR.PError2",      11, 2)      IF @P2Num > 0      BEGIN         SELECT @iLoop = 0         WHILE @iLoop < @P2Num         BEGIN            SELECT @iLoop = @iLoop + 1            SELECT @PrintText = 'PRINT.Resultset.2: Line ' +       CONVERT(char(2), @iLoop)            PRINT @PrintText         END      END      IF @E2Num > 0      BEGIN         SELECT @iLoop = 0         WHILE @iLoop < @E2Num         BEGIN            SELECT @iLoop = @iLoop + 1            SELECT @iErrNum = @iLoop + 202000            RAISERROR ("RAISERROR.Resultset.2", 11, 2)         END      END      /*   Return & Output ************************************ */             select @SetRtn = -1      RETURN @SetRtn      GO
  2. Δημιουργήστε ένα πρότυπο. Έργο EXE στη Visual Basic. Οι Φόρμα1 δημιουργούνται από προεπιλογή.
  3. Από το μενού έργο, επιλέξτε αναφορές και επιλέξτε τη βιβλιοθήκη αντικειμένων δεδομένων Microsoft ActiveX. Σημείωση: πρέπει να χρησιμοποιήσετε το ADO έκδοση 2,0 ή νεότερη για να λειτουργήσει σωστά ο κώδικας. Μπορείτε να αποκτήσετε τα πιο πρόσφατα στοιχεία του Microsoft Data Access Components (MDAC) στο Web στην παρακάτω διεύθυνση URL:
  4. Τοποθετήστε ένα κουμπί εντολής στη φόρμα και, στη συνέχεια, επικολλήστε τον παρακάτω κώδικα στην ενότητα γενικές δηλώσεις της φόρμας: Σημείωση: Ίσως χρειαστεί να αλλάξετε τη συμβολοσειρά σύνδεσης βάσης δεδομένων για το περιβάλλον σας.
          'This Code demonstrates RAISERROR/PRINT/RETURN values with ADO and      'multiple resultsets.      Sub CreateParms()      Dim ADOCmd As New ADODB.Command      Dim ADOPrm As New ADODB.Parameter      Dim ADOCon As ADODB.Connection      Dim ADORs As ADODB.Recordset      Dim sParmName As String      Dim strConnect As String      Dim rStr As String      On Error GoTo ErrHandler      strConnect = "driver={SQL        Server};server=(local);uid=sa;pwd=;database=pubs"      Set ADOCon = New ADODB.Connection      With ADOCon          .Provider = "MSDASQL"          .CursorLocation = adUseServer  'Must use Server side cursor.          .ConnectionString = strConnect          .Open      End With      Set ADOCmd.ActiveConnection = ADOCon      With ADOCmd          .CommandType = adCmdStoredProc          .CommandText = "ADOTestRPE"      End With      'Parameter 0 is the stored procedure Return code.      sParmName = "Return"      Set ADOPrm = ADOCmd.CreateParameter(sParmName, adInteger, _        adParamReturnValue, , 0)      ADOCmd.Parameters.Append ADOPrm      ADOCmd.Parameters(sParmName).Value = -1      'Parameter 1 is the setting for the stored procedure Output      ' parameter.      sParmName = "Output"      Set ADOPrm = ADOCmd.CreateParameter(sParmName, adInteger, _        adParamOutput)      ADOCmd.Parameters.Append ADOPrm      ADOCmd.Parameters(sParmName).Value = 999      'Parameter 2      sParmName = "R1Num"     'Number of rows to return in Resultset 1.      Set ADOPrm = ADOCmd.CreateParameter(sParmName, adInteger, _        adParamInput)      ADOCmd.Parameters.Append ADOPrm      ADOCmd.Parameters(sParmName).Value = 1      'Parameter 3      sParmName = "P1Num"     'Number of PRINT statements in Resultset 1.      Set ADOPrm = ADOCmd.CreateParameter(sParmName, adInteger, _       adParamInput)      ADOCmd.Parameters.Append ADOPrm      ADOCmd.Parameters(sParmName).Value = 0      'Parameter 4      sParmName = "E1Num"     'Number of RAISERROR statements in Resultset                              '1.      Set ADOPrm = ADOCmd.CreateParameter(sParmName, adInteger, _        adParamInput)      ADOCmd.Parameters.Append ADOPrm      ADOCmd.Parameters(sParmName).Value = 0      'Parameter 5      sParmName = "R2Num"     'Number of rows to return in Resultset 2.      Set ADOPrm = ADOCmd.CreateParameter(sParmName, adInteger, _        adParamInput)      ADOCmd.Parameters.Append ADOPrm      ADOCmd.Parameters(sParmName).Value = 2      'Parameter 6      sParmName = "P2Num"     'Number of PRINT statements in Resultset 2.      Set ADOPrm = ADOCmd.CreateParameter(sParmName, adInteger, _        adParamInput)      ADOCmd.Parameters.Append ADOPrm      ADOCmd.Parameters(sParmName).Value = 0      'Parameter 7      sParmName = "E2Num"     'Number of RAISERROR statements in Resultset                              ' 2.      Set ADOPrm = ADOCmd.CreateParameter(sParmName, adInteger, _       adParamInput)      ADOCmd.Parameters.Append ADOPrm      ADOCmd.Parameters(sParmName).Value = 0      Set ADORs = ADOCmd.Execute      Do While (Not ADORs Is Nothing)          If ADORs.State = adStateClosed Then Exit Do          While Not ADORs.EOF              For i = 0 To ADORs.Fields.Count - 1                  rStr = rStr & " : " & ADORs(i)              Next i              Debug.Print Mid(rStr, 3, Len(rStr))              ADORs.MoveNext              rStr = ""          Wend          Debug.Print "----------------------"          Set ADORs = ADORs.NextRecordset      Loop      Debug.Print "Return: " & ADOCmd.Parameters("Return").Value      Debug.Print "Output: " & ADOCmd.Parameters("Output").Value      GoTo Shutdown      ErrHandler:          Call ErrHandler(ADOCon)          Resume Next      Shutdown:          Set ADOCmd = Nothing          Set ADOPrm = Nothing          Set ADORs = Nothing          Set ADOCon = Nothing      End Sub      Private Sub Command1_Click()      Call CreateParms      End Sub      Sub ErrHandler(objCon As Object)      Dim ADOErr As ADODB.Error      Dim strError As String      For Each ADOErr In objCon.Errors       strError = "Error #" & ADOErr.Number & vbCrLf & ADOErr.Description _          & vbCr & _           "   (Source: " & ADOErr.Source & ")" & vbCr & _           "   (SQL State: " & ADOErr.SQLState & ")" & vbCr & _           "   (NativeError: " & ADOErr.NativeError & ")" & vbCr       If ADOErr.HelpFile = "" Then           strError = strError & "   No Help file available" & vbCr & vbCr       Else           strError = strError & "   (HelpFile: " & ADOErr.HelpFile & ")" _       & vbCr & _                       "   (HelpContext: " & ADOErr.HelpContext & ")" & _       vbCr & vbCr       End If       Debug.Print strError      Next      objCon.Errors.Clear      End Sub
  5. Αλλάξτε την τιμή των παραμέτρων δύο έως επτά για να αλλάξετε τον αριθμό των δηλώσεων ΕΚΤΎΠΩΣΗς ή/και των δηλώσεων RAISERROR που δημιουργούνται από την αποθηκευμένη διαδικασία και επιστρέφονται μέσω του ADO. Εκτελέστε ξανά το δείγμα κώδικα της Visual Basic και Σημειώστε ότι οι προτάσεις RAISERROR και PRINT επιστρέφονται μέσω της συλλογής σφαλμάτων του ADO. Αλλάξτε τις τιμές για να πειραματιστείτε με διαφορετικούς συνδυασμούς των δηλώσεων PRINT/RAISERROR με διαφορετικές συνόλων. Ανατρέξτε στις αποθηκευμένες διαδικασίες SQL για συγκεκριμένες λύσεις για ειδικές περιπτώσεις. Σημείωση: για να ανακτήσετε μια τιμή ΕΠΙΣΤΡΟΦΉς στο ADO με μια αποθηκευμένη διαδικασία, πρέπει να υπάρχει τουλάχιστον μία resultset. Για να επιλύσετε αυτό το πρόβλημα, όταν δεν έχουν καθοριστεί συνόλων (στο δείγμα κώδικα ADO), η αποθηκευμένη διαδικασία εκτελεί μια επιλογή NULL για να επιστρέψει μια τιμή null resultset στο ADO, συμπληρώνοντας έτσι την τιμή ΕΠΙΣΤΡΟΦΉς. Επιπλέον, για να επιλύσετε το ζήτημα του προσδιορισμού χωρίς προτάσεις RAISERROR και ενός συνδυασμού δηλώσεων ΕΚΤΎΠΩΣΗς, δημιουργούνται προεπιλεγμένες προτάσεις RAISERROR για να παρέχουν ένα περιβάλλον για την επιστροφή της δήλωσης ΕΚΤΎΠΩΣΗς μέσω του ADO. Πρέπει να έχετε κώδικα RAISERROR προτάσεις με τη μορφή που εμφανίζεται στην αποθηκευμένη διαδικασία, επειδή μόνο τα επίπεδα σοβαρότητας του 11-18 επιστρέφουν στη συλλογή σφαλμάτων του ADO.

Αναφορές


Βοήθεια Transact-SQL: Search on: "Εκτύπωση/RAISERROR πρόταση" για περισσότερες πληροφορίες, ανατρέξτε στο ακόλουθο άρθρο της Γνωσιακής Βάσης της Microsoft:
190988 Πώς μπορείτε να ανοίξετε ομάδες εγγραφών ADO ασύγχρονα χρησιμοποιώντας το WithEvents