Recuperare valori nelle stored procedure SQL Server con ADO

Questo articolo illustra come recuperare i valori nelle stored procedure SQL Server con ADO.

Versione originale del prodotto: SQL Server
Numero KB originale: 194792

Riepilogo

Esistono problemi importanti da considerare quando si tenta di recuperare RAISERROR/PRINT/RETURN valori da SQL Server stored procedure tramite ActiveX Data Objects (ADO). Ecco tre problemi:

  • RAISERRORle istruzioni in SQL Server devono essere di livello di gravità 11-18.

  • Le istruzioni PRINT in SQL Server possono anche popolare la raccolta di errori ADO. Tuttavia, le istruzioni PRINT sono di livello di gravità zero (0), quindi nella stored procedure è necessaria almeno un'istruzione RAISERROR per recuperare un'istruzione PRINT con ADO tramite l'insieme Errors.

  • I valori RETURN in una stored procedure devono essere associati ad almeno un set di risultati.

Ulteriori informazioni

L'esempio di codice seguente illustra l'esplorazione dell'insieme ADO Errors per accedere RAISERROR/PRINT/RETURN ai dettagli da una stored procedure SQL Server che restituisce più set di risultati:

  1. Incollare ed eseguire il codice seguente nella finestra SQL Server Management Studio (SSMS) dopo aver creato il database Pubs per creare la stored procedure usata per l'esempio ADO nel passaggio 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. Creare un progetto .EXE Standard in Visual Basic. Form1 viene creato per impostazione predefinita.

  3. Scegliere Riferimenti dal menu Progetto e selezionare Microsoft ActiveX Data Objects Library.From the Project menu, choose References and select the Microsoft ActiveX Data Objects Library.

    Nota

    Per il corretto funzionamento del codice, è necessario usare ADO versione 2.0 o successiva. È possibile ottenere i componenti MDAC (Microsoft Data Access Components) più recenti sul Web all'indirizzo: MDAC.

  4. Inserire un pulsante Di comando nel form e quindi incollare il codice seguente nella sezione General Declarations (Dichiarazioni generali) del form. Potrebbe essere necessario modificare la stringa di connessione del database per l'ambiente.

    '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. Modificare il valore dei parametri da due a sette per modificare il numero di PRINT istruzioni e/o RAISERROR istruzioni generate dalla stored procedure e restituite tramite ADO. Eseguire di nuovo l'esempio di codice di Visual Basic e notare che le RAISERROR istruzioni e PRINT vengono restituite tramite la raccolta di errori ADO. Modificare i valori per sperimentare combinazioni diverse di istruzioni con set di PRINT/RAISERROR risultati diversi. Per informazioni su soluzioni alternative specifiche per casi speciali, vedere le stored procedure SQL.

Per recuperare un valore RETURN in ADO con una stored procedure, deve essere presente almeno un set di risultati. Per risolvere questo problema, quando non vengono specificati set di risultati (nel codice di esempio ADO) la stored procedure esegue un'istruzione SELECT NULL per restituire un set di risultati Null ad ADO popolando in tal modo il valore RETURN. Inoltre, per risolvere il problema di non specificare istruzioni RAISERROR e una combinazione di PRINT istruzioni, vengono generate istruzioni predefinite RAISERROR per fornire un contesto per la restituzione dell'istruzione PRINT tramite ADO. Le istruzioni di codice RAISERROR devono essere nel formato illustrato nella stored procedure perché solo i livelli di gravità 11-18 vengono restituiti tramite la raccolta di errori ADO.

Riferimenti

RAISERROR (Transact-SQL)