Ir para conteúdo
Fórum Script Brasil
  • 0

(Resolvido) Stored Procedure com passagem de parâmetros Output


Xistyle

Pergunta

Pessoal, boa tarde!

Gostaria de uma ajuda. Preciso montar uma função VB genérica para executar Stored Procedures (SPs) e retornar um valor destas. No caso, essas SPs irão retornar a ID do registro que acabou de ser incluído. Como o projeto usa Selects com o comando "WITH (NOLOCK)", está ocorrendo a perda da ID correta caso seja usado o comando Select Max().

O sistema está em uso por uma empresa e vários usuários realizam cadastros quase simultaneamente. Normalmente, ao inserir uma informação, é dado um Select Max para atribuir a ID do registro recém inserido à uma variável no VB. Porém, devido ao explicado acima, está ocorrendo a troca de IDs.

Ai veio a idéia de testar o retorno de informação das SPs com SCOPE IDENTITY, para ter maior segurança com os dados inseridos e ter a confiança que trará a ID correta. Porém, cada SP tem uma quantidade de parâmetros que são passados. Então teria que montar uma função genérica para, de acordo com a SP, inserir os parâmetros. É a primeira vez que uso o ADODB.Parameters e estou meio perdido.

Segue abaixo o código:

Public Function gfcnExecutarIDAtual(ByVal lstrProcedure As String, _
                             ByRef lstrParametros() As String) As Variant
                             
Dim llngContador           As Long                'Usado para o laço dos parâmetros
Dim lstrSQL                   As String              'Usado para retornar os nomes dos parâmetros da SP  
Dim lcmmExecute          As New ADODB.Command
Dim ladoParametro        As New ADODB.Parameter
Dim lrsDados                As ADODB.Recordset
Dim ladoTipo                 As ADODB.DataTypeEnum
Dim ladoEntradaSaida    As ADODB.ParameterDirectionEnum
   
    gfcnExecutarIDAtual = 0

    With lcmmExecute
    
        .ActiveConnection = gconConexao
        .CommandType = adCmdText
       
        If UBound(lstrParametros) >= 0 Then
                   
            '# Retorna o nome das colunas/parâmetros da SP
            lstrSQL = "sp_sproc_columns " & lstrProcedure
            
            Set lrsDados = New ADODB.Recordset
            
            lrsDados.CursorType = adOpenForwardOnly
            lrsDados.CursorLocation = adUseClient
            lrsDados.LockType = adLockReadOnly
            lrsDados.Open lstrSQL, gconConexao, , , adCmdText
            
            '# O primeiro parâmetro sempre é RETURN_VALUE. Não iremos trabalhar com ele.
            If lrsDados(eParametrosSP.eNomeParametro).Value = "@RETURN_VALUE" Then lrsDados.MoveNext
            
            .CommandType = CommandTypeEnum.adCmdStoredProc
            
            '# É adicionado mais um ao índice máximo do vetor para que seja incluído
            '# o parâmetro que retorna a IDAtual (@O_IDATUAL)
            For llngContador = 0 To (UBound(lstrParametros) + 1)
                
                '# Verifica o tipo do parâmetro - Coluna 6
                Select Case UCase(CStr(lrsDados.Fields.Item(eParametrosSP.eTipoParametro)))
                    
                    Case "INT"
                        ladoTipo = ADODB.DataTypeEnum.adInteger
                        
                    Case "NUMERIC"
                        ladoTipo = ADODB.DataTypeEnum.adNumeric
                    
                    Case "VARCHAR"
                        ladoTipo = ADODB.DataTypeEnum.adVarChar
                    
                End Select
               
                '# Verifica se é um parâmetro de Entrada ou Saída
                If Mid(CStr(lrsDados(eParametrosSP.eNomeParametro).Value), 1, 2) = "@I" Then
                    ladoEntradaSaida = ADODB.ParameterDirectionEnum.adParamInput
                Else
                    ladoEntradaSaida = ADODB.ParameterDirectionEnum.adParamOutput
                End If
                
                '# O parâmetro de saída (retorno) não passa valores
                If llngContador <= UBound(lstrParametros) Then
                    .Parameters.Append .CreateParameter(lrsDados(eParametrosSP.eNomeParametro).Value, ladoTipo, ladoEntradaSaida, , lstrParametros(llngContador))
                Else
                    .Parameters.Append .CreateParameter(lrsDados(eParametrosSP.eNomeParametro).Value, ladoTipo, ladoEntradaSaida)
                End If
                
                lrsDados.MoveNext
            Next
            
    
        End If
                
        .CommandText = lstrProcedure
        .Execute
        gfcnExecutarIDAtual = .Execute("@O_IDATUAL")

    End With
        
    Set lrsDados = Nothing
    Set lcmmExecute = Nothing

End Function

Como pode ser visto, os parâmetros são portanto criados dinamicamente. Neste laço que estou testando, com 3 parâmetros, a primeira execução ocorre corretamente (passando pelo primeiro Parameter.Append). Logo após isso, ao tentar passar novamente pelo primeiro Append, ocorre um erro. Como os valores mudaram e não entendo muito desse objeto, não entendi o motivo do erro. Em vários lugares que pesquisei não achei nada anormal com o código.

O erro é o seguinte: "Objeto Parameter definido incorretamente. As informações são inconsistentes ou incompletas."

Poderiam me ajudar?

Editado por Xistyle
Link para o comentário
Compartilhar em outros sites

6 respostass a esta questão

Posts Recomendados

  • 0

Senhores, consegui resolver!

Apesar de ter alguns parâmetros opcionais (.CreateParameter), ele dá algum erro caso não seja passado por completo. Estranho né?

Bom, além disso, tive que "calibrar" os parâmetros passados. Para os campos que são declarados como Numeric, devem ser passados a precision e scale (Campo Porcentagem Numeric(10,2)). Assim, ocorreu tudo certinho.

Abaixo o código. Achei bem interessante as pesquisas que fiz e a utilidade dele. Por ser uma rotina genérica, pode ser usada facilmente. Estou terminando alguns testes (testei apenas em 2 SPs).

Abraços

Public Function gfcnExecutarIDAtual(ByVal lstrProcedure As String, _
                             ByRef lstrParametros() As String) As Single
                             
Dim llngContador        As Long
Dim lintTamanho         As Integer
Dim lintEscala          As Integer
Dim lstrSQL             As String
Dim lcmmExecute         As New ADODB.Command
Dim ladoParametro       As New ADODB.Parameter
Dim lrsDados            As ADODB.Recordset
Dim ladoTipo            As ADODB.DataTypeEnum
Dim ladoEntradaSaida    As ADODB.ParameterDirectionEnum
    
On Error GoTo erro
    
    gfcnExecutarIDAtual = 0
   
    With lcmmExecute
    
        .ActiveConnection = gconConexao
        .CommandType = adCmdText
                
        lintTamanho = 0
                
        If UBound(lstrParametros) >= 0 Then
                   
            '# Retorna o nome das colunas/parâmetros da SP
            lstrSQL = "sp_sproc_columns " & lstrProcedure
            
            Set lrsDados = New ADODB.Recordset
            
            lrsDados.CursorType = adOpenForwardOnly
            lrsDados.CursorLocation = adUseClient
            lrsDados.LockType = adLockReadOnly
            lrsDados.Open lstrSQL, gconConexao, , , adCmdText
            
            If lrsDados(eParametrosSP.eNomeParametro).Value = "@RETURN_VALUE" Then lrsDados.MoveNext
            
            .CommandType = CommandTypeEnum.adCmdStoredProc
            .CommandText = lstrProcedure
            
            '# É adicionado mais um ao índice máximo do vetor para que seja incluído
            '# o parâmetro que retorna a IDAtual (@O_IDATUAL)
            For llngContador = 0 To (UBound(lstrParametros))
                
                '# Verifica o tipo do parâmetro - Coluna 6
                Select Case UCase(CStr(lrsDados.Fields.Item(eParametrosSP.eTipoParametro)))
                    
                    Case "INT"
                        ladoTipo = ADODB.DataTypeEnum.adInteger
                        
                    Case "NUMERIC"
                        ladoTipo = ADODB.DataTypeEnum.adNumeric
                    
                    Case "VARCHAR"
                        ladoTipo = ADODB.DataTypeEnum.adVarChar
                    
                End Select
                
                '# Recebe o tamanho máximo do campo
                lintTamanho = lrsDados(eParametrosSP.eTamanhoCampo).Value
               
                '# Verifica se é um parâmetro de Entrada ou Saída
                If Mid(CStr(lrsDados(eParametrosSP.eNomeParametro).Value), 1, 2) = "@I" Then
                    ladoEntradaSaida = ADODB.ParameterDirectionEnum.adParamInput
                Else
                    ladoEntradaSaida = ADODB.ParameterDirectionEnum.adParamOutput
                End If
               
                '# O parâmetro de saída (retorno) não passa valores
                If ladoEntradaSaida <> ADODB.ParameterDirectionEnum.adParamOutput Then
                    
                    .Parameters.Append .CreateParameter(lrsDados(eParametrosSP.eNomeParametro).Value, ladoTipo, ladoEntradaSaida, lintTamanho, IIf(UCase(lstrParametros(llngContador)) = "NULL", 0, lstrParametros(llngContador)))
                    
                    '# Recebe a escala e precisão, caso haja
                    If ladoTipo <> ADODB.DataTypeEnum.adVarChar Then
                        .Parameters.Item(llngContador).Precision = lintTamanho
                        .Parameters.Item(llngContador).NumericScale = lrsDados(eParametrosSP.eEscala).Value
                    End If
                
                Else

                    .Parameters.Append .CreateParameter(lrsDados(eParametrosSP.eNomeParametro).Value, ladoTipo, ladoEntradaSaida, lintTamanho)
                    
                    '# Recebe a escala e precisão, caso haja
                    If ladoTipo <> ADODB.DataTypeEnum.adVarChar Then
                        .Parameters.Item(llngContador).Precision = lintTamanho
                        .Parameters.Item(llngContador).NumericScale = lrsDados(eParametrosSP.eEscala).Value
                    End If
                    
                End If
                
                lrsDados.MoveNext
            Next
    
        End If
        
        .Execute
        gfcnExecutarIDAtual = .Parameters("@O_IDATUAL")

    End With
        
    Set lrsDados = Nothing
    Set lcmmExecute = Nothing
    Set ladoParametro = Nothing

    Exit Function
    
erro:

    Set lcmmExecute = Nothing
    gfcnExecutarIDAtual = False
    frmErro.letstrCodigoErro = Err.Number
    frmErro.letstrDescricaoErro = Err.Description & vbCrLf & "Instrução: gfcnExecutarIDAtual"
    
End Function

Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,3k
    • Posts
      652,3k
×
×
  • Criar Novo...