Capítulo 19: Conexão Direta com Banco de Dados Relacional via ADODB e SQL

🎯 Objetivo da Aula

Nesta aula, você aprenderá a transformar o Microsoft Excel em uma poderosa interface de consulta para bancos de dados corporativos utilizando a biblioteca ADODB (ActiveX Data Objects Database) e a linguagem SQL (Structured Query Language). Você aprenderá a estabelecer uma conexão ativa com arquivos de banco de dados Access (ADODB.Connection), executar instruções SELECT filtradas, extrair cabeçalhos dinâmicos dos metadados e despejar milhares de registros na planilha com o método de alta performance CopyFromRecordset.

Ao final desta aula, você terá construído o conector analítico direto entre o Excel e o banco de dados relacional SIG_FastLog_Dados.accdb.


🏢 Cenário Prático (FastLog S.A.)

Empresa: FastLog Transportes & Logística Integrada S.A.
Problema: A equipe de manutenção mecânica e suprimentos controla o estoque de peças de reposição de carretas (filtros, lonas de freio, baterias e pneus) em um banco de dados relacional centralizado do Access (SIG_FastLog_Dados.accdb), criado pelo time de TI. Para saber quais peças estavam em nível crítico de estoque, o comprador precisava pedir para o analista de banco abrir o Access, executar uma consulta manual, exportar um arquivo e enviar por e-mail. Esse processo levava até 4 horas, atrasando a compra de peças e deixando caminhões parados no pátio esperando manutenção.
Sua Missão: Desenvolver o módulo em VBA ConsultarEstoqueCriticoADODB, que se conecta diretamente ao banco de dados relacional em segundo plano, executa uma instrução SQL com filtro de estoque mínimo e descarrega a relação de peças a serem compradas na planilha em 0,1 segundo.


🧠 Fundamentos: A Teoria Traduzida

1. A Arquitetura ADODB no Excel

O ADODB é o padrão corporativo da Microsoft para comunicação entre aplicações e bancos de dados relacionais (Access, SQL Server, Oracle, PostgreSQL). Ele atua através de dois objetos primordiais:

flowchart LR
    EXCEL["📊 Excel (VBA)"] <--> CONN["🔌 ADODB.Connection<br/>(Canal de Comunicação Aberto)"]
    CONN <--> DB[("🗄️ Banco de Dados Relacional<br/>SIG_FastLog_Dados.accdb")]
    DB -- "Executa Consulta SQL<br/>SELECT * FROM Pecas..." --> RS["📑 ADODB.Recordset<br/>(Tabela Virtual em Memória)"]
    RS -- "Range.CopyFromRecordset (0,05 s)" --> EXCEL

    style EXCEL fill:#217346,stroke:#fff,stroke-width:2px,color:#fff
    style CONN fill:#1a365d,stroke:#fff,stroke-width:2px,color:#fff
    style DB fill:#8e44ad,stroke:#fff,stroke-width:2px,color:#fff
    style RS fill:#27ae60,stroke:#fff,stroke-width:2px,color:#fff

2. A Cadeia de Conexão (Connection String)

Para o Excel saber onde o banco de dados está e qual driver utilizar, passamos uma Connection String. Para bancos de dados Microsoft Access contemporâneos (.accdb), utilizamos o provedor oficial Microsoft.ACE.OLEDB.12.0 (ou 16.0):

1
strConexao = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\FastLog_Dados\SIG_FastLog_Dados.accdb;"

3. O Método Ultrarrápido CopyFromRecordset

O Excel possui um método embutido no objeto Range desenvolvido exclusivamente para o ADODB. Em vez de percorrer o banco com um laço linha a linha, o comando:

1
Range("A2").CopyFromRecordset rs

despeja todos os registros retornados pela consulta SQL diretamente nas células com velocidade de barramento de memória!


📖 Exemplo Guiado: Passo a Passo no Laboratório

No computador do laboratório, acesse o VBE com Alt + F11.

Passo 1: Inserção do Módulo de Banco de Dados

  1. No menu superior, clique em Inserir ➔ Módulo.
  2. Na janela de propriedades (F4), renomeie o módulo para: modConexaoADODB.
  3. Confirme a presença de Option Explicit.

🛠️ Prática Obrigatória 1: Conexão com Access e Despejo via CopyFromRecordset

Construiremos a rotina oficial que se conecta ao banco de dados e executa uma consulta SQL filtrando peças abaixo do estoque mínimo de segurança.

Passo a Passo no Computador:

  1. No módulo modConexaoADODB, digite o seguinte código completo:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    
    Option Explicit
    
    Sub ConsultarEstoqueCriticoADODB()
        Dim cnn As Object
        Dim rs As Object
        Dim ws As Worksheet
        Dim strCaminhoBanco As String
        Dim strConexao As String
        Dim strSQL As String
        Dim i As Long
        Dim lngTotalRegistros As Long
        Dim tInicio As Double
    
        Set ws = ThisWorkbook.Worksheets(1)
        tInicio = Timer
    
        ' 1. Localização do Banco de Dados
        ' Suponha o banco localizado na mesma pasta desta planilha
        strCaminhoBanco = ThisWorkbook.Path & "\SIG_FastLog_Dados.accdb"
    
        ' Se o arquivo não existir localmente, cria caminho alternativo para simulação
        If Dir(strCaminhoBanco) = "" Then
            strCaminhoBanco = "C:\FastLog_Dados\SIG_FastLog_Dados.accdb"
        End If
    
        ' 2. Instanciação dos Objetos ADODB via Late Binding
        Set cnn = CreateObject("ADODB.Connection")
        Set rs = CreateObject("ADODB.Recordset")
    
        ' String de conexão com o provedor OLEDB do Access
        strConexao = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strCaminhoBanco & ";"
    
        On Error GoTo TratarErroConexao
        cnn.Open strConexao
    
        ' 3. Instrução SQL Filtrando Peças Críticas
        strSQL = "SELECT CodigoPeca, NomePeca, Categoria, QtdEstoque, EstoqueMinimo, PrecoUnitario " & _
                 "FROM Pecas " & _
                 "WHERE QtdEstoque <= EstoqueMinimo " & _
                 "ORDER BY QtdEstoque ASC;"
    
        rs.Open strSQL, cnn, 1, 1 ' 1 = adOpenKeyset, 1 = adLockReadOnly
    
        ' 4. Limpeza da Planilha de Exibição
        ws.Cells.Clear
    
        ' 5. Extração Dinâmica dos Cabeçalhos das Colunas a partir do Banco
        For i = 0 To rs.Fields.Count - 1
            With ws.Cells(1, i + 1)
                .Value = UCase(rs.Fields(i).Name)
                .Font.Bold = True
                .Font.Color = RGB(255, 255, 255)
                .Interior.Color = RGB(0, 51, 102) ' Azul FastLog
                .HorizontalAlignment = xlCenter
            End With
        Next i
    
        ' 6. DESPEJO EM MASSA DO RECORDSET NA PLANILHA
        If Not rs.EOF Then
            ws.Range("A2").CopyFromRecordset rs
    
            ' Formatações de moeda e quantidade
            lngTotalRegistros = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row - 1
            ws.Range("D2:E" & (lngTotalRegistros + 1)).NumberFormat = "#,##0"
            ws.Range("F2:F" & (lngTotalRegistros + 1)).NumberFormat = "R$ #,##0.00"
            ws.Columns("A:F").AutoFit
    
            MsgBox "Consulta SQL executada com sucesso!" & vbCrLf & vbCrLf & _
                   "• Peças em nível crítico: " & lngTotalRegistros & vbCrLf & _
                   "• Tempo de Execução: " & Format(Timer - tInicio, "0.000") & " segundos.", _
                   vbInformation, "FastLog ADODB Integration"
        Else
            MsgBox "Nenhuma peça com estoque crítico no momento!", vbInformation, "Estoque Regular"
        End If
    
        ' 7. Fechamento Limpo das Conexões
        rs.Close
        cnn.Close
        Set rs = Nothing
        Set cnn = Nothing
        Exit Sub
    
    TratarErroConexao:
        MsgBox "FALHA NA CONEXÃO COM BANCO DE DADOS:" & vbCrLf & vbCrLf & _
               "• Erro: " & Err.Description & vbCrLf & _
               "• Verifique se o arquivo 'SIG_FastLog_Dados.accdb' está acessível.", _
               vbCritical, "Erro de Banco Relacional"
        If Not rs Is Nothing Then If rs.State = 1 Then rs.Close
        If Not cnn Is Nothing Then If cnn.State = 1 Then cnn.Close
        Set rs = Nothing
        Set cnn = Nothing
    End Sub

✅ Resultado Esperado (Prática 1):

A macro conecta-se ao banco relacional do Access, extrai os nomes das colunas de forma automática e descarrega a tabela de peças críticas na planilha em milissegundos.


🛠️ Prática Obrigatória 2: Atualização Direta no Banco via Instrução SQL UPDATE

Agora realizaremos a operação de escrita: enviaremos um comando SQL UPDATE direto para o banco de dados através da conexão ADODB, atualizando o estoque de uma peça sem precisar abrir o Access.

Passo a Passo no Computador:

  1. No mesmo módulo, insira o procedimento de atualização transacional:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    
    Sub AtualizarEstoqueNoBanco()
        Dim cnn As Object
        Dim strCaminhoBanco As String
        Dim strConexao As String
        Dim strSQL As String
        Dim strCodigoPeca As String
        Dim lngNovaQuantidade As Long
        Dim lngLinhasAfetadas As Long
    
        ' Coleta dos parâmetros via InputBox
        strCodigoPeca = UCase(Trim(InputBox("Digite o código da peça que recebeu reposição (ex: PEC-101):", "Entrada Estoque")))
        If strCodigoPeca = "" Then Exit Sub
    
        lngNovaQuantidade = CLng(InputBox("Digite a quantidade de itens a adicionar ao estoque:", "Entrada Estoque"))
        If lngNovaQuantidade <= 0 Then Exit Sub
    
        strCaminhoBanco = ThisWorkbook.Path & "\SIG_FastLog_Dados.accdb"
        If Dir(strCaminhoBanco) = "" Then strCaminhoBanco = "C:\FastLog_Dados\SIG_FastLog_Dados.accdb"
    
        Set cnn = CreateObject("ADODB.Connection")
        strConexao = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strCaminhoBanco & ";"
    
        On Error GoTo TratarErro
        cnn.Open strConexao
    
        ' Monta instrução SQL de atualização
        strSQL = "UPDATE Pecas " & _
                 "SET QtdEstoque = QtdEstoque + " & lngNovaQuantidade & " " & _
                 "WHERE CodigoPeca = '" & strCodigoPeca & "';"
    
        ' Executa o comando SQL diretamente no motor do banco
        cnn.Execute strSQL, lngLinhasAfetadas
    
        cnn.Close
        Set cnn = Nothing
    
        If lngLinhasAfetadas > 0 Then
            MsgBox "Estoque atualizado com sucesso no banco de dados!" & vbCrLf & _
                   "• Peça: " & strCodigoPeca & vbCrLf & _
                   "• Quantidade Adicionada: +" & lngNovaQuantidade, _
                   vbInformation, "Persistência SQL Concluída"
    
            ' Atualiza a planilha chamando a consulta anterior
            Call ConsultarEstoqueCriticoADODB
        Else
            MsgBox "Peça não localizada no banco de dados: " & strCodigoPeca, vbExclamation, "Aviso"
        End If
    
        Exit Sub
    
    TratarErro:
        MsgBox "Erro ao atualizar banco de dados: " & Err.Description, vbCritical, "Erro SQL"
        If Not cnn Is Nothing Then If cnn.State = 1 Then cnn.Close
        Set cnn = Nothing
    End Sub
  2. Execute a macro AtualizarEstoqueNoBanco:
    • Digite o código de uma peça e informe a quantidade reposta.
    • O banco Access é atualizado diretamente e a planilha reflete a nova situação imediatamente!

✅ Resultado Esperado (Prática 2):

O Excel atua como uma aplicação executiva completa de consulta e atualização de registros relacionais.


📤 Instruções de Entrega (Microsoft Teams)

  1. Salve sua pasta de trabalho corporativa (.xlsm).
  2. Nomeie o arquivo: Atividade_19_VBA_SeuNome_SeuSobrenome.xlsm.
  3. Acesse o Microsoft Teams na sala da disciplina.
  4. Abra a tarefa: “VBA - Cap 19: Conexão ADODB e Banco de Dados SQL”.
  5. Anexe a pasta de trabalho e entregue.

💡 Checkpoint de Gestão & TI

A separação entre a interface de trabalho (Front-End) no Excel e a base de persistência (Back-End) em um banco relacional como Access ou SQL Server é a melhor arquitetura de TI corporativa. Planilhas compartilhadas na rede tendem a corromper quando mais de 5 pessoas gravam simultaneamente. Ao delegar o armazenamento a um banco relacional via ADODB, a integridade referencial e o controle de concorrência ficam sob a guarda do motor de banco de dados, enquanto os gestores continuam desfrutando do conforto analítico do Excel.


🔥 Desafio de Fixação: Consulta SQL Dinâmica com Filtro de Categoria

Adicione ao formulário ou célula um filtro por categoria:

  1. Permita que o operador digite a categoria desejada na célula H1 (ex: "Filtros", "Freios" ou "Pneus").
  2. Se a célula H1 estiver preenchida, altere dinamicamente a instrução SQL para incluir a cláusula:
    1
    
    strSQL = strSQL & " AND Categoria = '" & ws.Range("H1").Value & "' "
  3. Teste filtrando apenas pneus abaixo do estoque mínimo!

🔑 Revelar Gabarito Oficial de Laboratório (Clique para expandir)
💡 Incentivo Pedagógico: Tente resolver as práticas e o desafio de fixação por conta própria antes de abrir o gabarito. Seus erros e tentativas durante o laboratório são a chave para a consolidação real do aprendizado!

Código Consolidado (modConexaoADODB):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Option Explicit

Sub ConsultarEstoqueComFiltroCategoria()
    Dim cnn As Object, rs As Object
    Dim ws As Worksheet
    Dim strBanco As String, strSQL As String
    Dim strFiltroCat As String
    Dim i As Long
    
    Set ws = ThisWorkbook.Worksheets(1)
    strBanco = ThisWorkbook.Path & "\SIG_FastLog_Dados.accdb"
    If Dir(strBanco) = "" Then strBanco = "C:\FastLog_Dados\SIG_FastLog_Dados.accdb"
    
    strFiltroCat = Trim(ws.Range("H1").Value)
    
    Set cnn = CreateObject("ADODB.Connection")
    Set rs = CreateObject("ADODB.Recordset")
    
    On Error GoTo TratarErro
    cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strBanco & ";"
    
    strSQL = "SELECT CodigoPeca, NomePeca, Categoria, QtdEstoque, EstoqueMinimo, PrecoUnitario " & _
             "FROM Pecas " & _
             "WHERE QtdEstoque <= EstoqueMinimo "
             
    If strFiltroCat <> "" Then
        strSQL = strSQL & "AND Categoria = '" & Replace(strFiltroCat, "'", "''") & "' "
    End If
    
    strSQL = strSQL & "ORDER BY QtdEstoque ASC;"
    
    rs.Open strSQL, cnn, 1, 1
    
    ws.Range("A2:F1000").ClearContents
    
    For i = 0 To rs.Fields.Count - 1
        ws.Cells(1, i + 1).Value = UCase(rs.Fields(i).Name)
        ws.Cells(1, i + 1).Font.Bold = True
    Next i
    
    If Not rs.EOF Then
        ws.Range("A2").CopyFromRecordset rs
        ws.Columns("A:F").AutoFit
    End If
    
    rs.Close
    cnn.Close
    Set rs = Nothing
    Set cnn = Nothing
    Exit Sub

TratarErro:
    MsgBox "Falha de Conexão SQL: " & Err.Description, vbCritical, "Erro ADODB"
    If Not rs Is Nothing Then If rs.State = 1 Then rs.Close
    If Not cnn Is Nothing Then If cnn.State = 1 Then cnn.Close
End Sub

📝 Atividade Extra: Questionário de Fixação (Caderno)

Instruções: Responda no caderno, de próprio punho, as 10 perguntas abaixo com base no que você estudou neste capítulo. Ao concluir, apresente o caderno ao professor para visto.

  1. O que representa a sigla ADODB e para que ela serve no desenvolvimento com VBA?
  2. Explique a diferença entre o objeto ADODB.Connection e o objeto ADODB.Recordset.
  3. O que é uma Connection String e qual provedor OLEDB é utilizado para conectar a bancos de dados Microsoft Access contemporâneos (.accdb)?
  4. Qual é o comando da linguagem SQL utilizado para realizar consultas e filtros de registros em tabelas?
  5. O que significa a cláusula WHERE QtdEstoque <= EstoqueMinimo dentro de uma instrução SQL?
  6. Por que o método Range("A2").CopyFromRecordset rs é muito superior a ler o banco com um laço While Not rs.EOF?
  7. Como extraímos automaticamente os nomes das colunas de uma consulta SQL para preencher o cabeçalho da planilha?
  8. Qual comando SQL é utilizado para atualizar dados existentes dentro de uma tabela relacional?
  9. O que a propriedade rs.EOF indica no ciclo de vida de um Recordset?
  10. Quais são as vantagens de segurança e integridade de dados ao separar o Front-End no Excel do Back-End no Access?