VBA avansat în Excel: automatizează rapoarte complexe fără să fii programator
Macrourile înregistrate sunt un început bun. Dar se opresc acolo unde apare prima condiție, primul buclă, prima decizie.
VBA (Visual Basic for Applications) e limbajul care îți permite să construiești automatizări reale — rapoarte generate automat din date brute, fișiere create și salvate cu un click, emailuri trimise direct din Excel.
Acest ghid e pentru utilizatorul Excel avansat care vrea să treacă pragul de la „record macro” la cod real care rezolvă probleme reale.
Structura unui proiect VBA bine organizat
Deschizi VBA Editor: Alt+F11
Organizarea codului:
- Module — proceduri și funcții reutilizabile (codul principal)
- ThisWorkbook — evenimente ale registrului de lucru (Workbook_Open, BeforeSave)
- Sheet modules — evenimente specifice foii (Worksheet_Change, SelectionChange)
- Clase (Class Modules) — pentru cod orientat-obiect (avansat)
Convenții de denumire:
' Proceduri (nu returnează valoare):
Sub GenereazaRaportLunar()
' Funcții (returnează valoare):
Function CalculeazaTVA(suma As Double) As Double
Lucrezi cu date: citire și scriere eficientă
Cea mai mare greșeală VBA: celulă cu celulă
Lent (evită):
For i = 1 To 10000
Cells(i, 1).Value = i * 2 ' 10.000 operații cu foaia
Next i
Rapid (folosește arrays):
Dim arr(1 To 10000, 1 To 1) As Long
For i = 1 To 10000
arr(i, 1) = i * 2 ' operație în memorie
Next i
Range("A1:A10000").Value = arr ' o singură scriere în foaie
Diferența de viteză: de 50-100x pe seturi mari de date.
Citire rapidă în array:
Dim data As Variant
data = Range("A1:D" & LastRow).Value ' tot tabelul în memorie
' Acum data(rând, coloană) - accesezi instant
Funcții utilitare pe care le scrii o dată și le refolosești
LastRow și LastCol — fundamentale
Function LastRow(ws As Worksheet, Optional col As Integer = 1) As Long
LastRow = ws.Cells(ws.Rows.Count, col).End(xlUp).Row
End Function
Function LastCol(ws As Worksheet, Optional row As Integer = 1) As Integer
LastCol = ws.Cells(row, ws.Columns.Count).End(xlToLeft).Column
End Function
SheetExists — verifici înainte să creezi
Function SheetExists(wb As Workbook, sheetName As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = wb.Sheets(sheetName)
SheetExists = Not ws Is Nothing
On Error GoTo 0
End Function
GetOrCreateSheet — creezi foaia dacă nu există
Function GetOrCreateSheet(wb As Workbook, sheetName As String) As Worksheet
If SheetExists(wb, sheetName) Then
Set GetOrCreateSheet = wb.Sheets(sheetName)
GetOrCreateSheet.Cells.Clear
Else
Set GetOrCreateSheet = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count))
GetOrCreateSheet.Name = sheetName
End If
End Function
Exemplu complet: raport lunar generat automat din date brute
Scenariul: ai o foaie „Date” cu toate tranzacțiile anului. La click pe un buton, generezi automat câte o foaie separată pentru fiecare lună, cu sumarul vânzărilor per agent.
Sub GenereazaRapoarteLunare()
Dim wsDate As Worksheet
Dim wsRaport As Worksheet
Dim data As Variant
Dim i As Long, ultimulRand As Long
Dim luna As Integer, lunaCurenta As Integer
Dim dictLuni As Object
' Optimizare: oprim refreshul ecranului
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Set wsDate = ThisWorkbook.Sheets("Date")
ultimulRand = LastRow(wsDate)
' Citim tot tabelul în memorie
data = wsDate.Range("A2:D" & ultimulRand).Value
' Coloana A: Data, B: Agent, C: Produs, D: Valoare
' Colectăm lunile unice
Set dictLuni = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(data, 1)
If IsDate(data(i, 1)) Then
luna = Month(data(i, 1))
If Not dictLuni.Exists(luna) Then
dictLuni.Add luna, MonthName(luna, False)
End If
End If
Next i
' Generăm câte o foaie per lună
Dim lunii As Variant
For Each lunii In dictLuni.Keys
Dim numeLuna As String
numeLuna = "Raport_" & Format(lunii, "00")
Set wsRaport = GetOrCreateSheet(ThisWorkbook, numeLuna)
' Antet raport
With wsRaport
.Range("A1").Value = "Raport Vânzări " & dictLuni(lunii) & " " & Year(Now)
.Range("A1").Font.Bold = True
.Range("A1").Font.Size = 14
.Range("A3:C3").Value = Array("Agent", "Nr. Tranzacții", "Total Vânzări")
.Range("A3:C3").Font.Bold = True
End With
' Calculăm per agent pentru luna respectivă
Dim dictAgenti As Object
Set dictAgenti = CreateObject("Scripting.Dictionary")
Dim dictCount As Object
Set dictCount = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(data, 1)
If IsDate(data(i, 1)) And Month(data(i, 1)) = lunii Then
Dim agent As String
agent = CStr(data(i, 2))
If Not dictAgenti.Exists(agent) Then
dictAgenti.Add agent, 0
dictCount.Add agent, 0
End If
dictAgenti(agent) = dictAgenti(agent) + data(i, 4)
dictCount(agent) = dictCount(agent) + 1
End If
Next i
' Scriem rezultatele
Dim randScriere As Long
randScriere = 4
Dim agentKey As Variant
For Each agentKey In dictAgenti.Keys
wsRaport.Cells(randScriere, 1).Value = agentKey
wsRaport.Cells(randScriere, 2).Value = dictCount(agentKey)
wsRaport.Cells(randScriere, 3).Value = dictAgenti(agentKey)
wsRaport.Cells(randScriere, 3).NumberFormat = "#,##0.00 lei"
randScriere = randScriere + 1
Next agentKey
' Total
wsRaport.Cells(randScriere, 1).Value = "TOTAL"
wsRaport.Cells(randScriere, 1).Font.Bold = True
wsRaport.Cells(randScriere, 3).Formula = "=SUM(C4:C" & randScriere - 1 & ")"
wsRaport.Cells(randScriere, 3).Font.Bold = True
' Formatare tabel
wsRaport.Range("A3:C" & randScriere).Borders.LineStyle = xlContinuous
wsRaport.Columns("A:C").AutoFit
Next lunii
' Restaurăm setările
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
MsgBox "Rapoarte generate: " & dictLuni.Count & " luni.", vbInformation
End Sub
Trimiterea automată de emailuri din Excel (Outlook)
Sub TrimiteRaportPeEmail()
Dim outlook As Object
Dim mail As Object
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Stoc_Curent")
' Verifică dacă există produse sub stoc minim
Dim nrAlerte As Long
nrAlerte = WorksheetFunction.CountIf(ws.Columns(5), "REAPROVIZIONARE URGENTĂ")
If nrAlerte = 0 Then
MsgBox "Nu sunt alerte de reaprovizionare."
Exit Sub
End If
' Salvează foaia ca PDF
Dim caleaPDF As String
caleaPDF = Environ("TEMP") & "\Alerte_Stoc_" & Format(Now, "YYYY-MM-DD") & ".pdf"
ws.ExportAsFixedFormat xlTypePDF, caleaPDF
' Creează emailul în Outlook
Set outlook = CreateObject("Outlook.Application")
Set mail = outlook.CreateItem(0)
With mail
.To = "achizitii@firma.ro"
.CC = "director@firma.ro"
.Subject = "ALERTĂ: " & nrAlerte & " produse necesită reaprovizionare - " & Format(Now, "DD.MM.YYYY")
.Body = "Bună ziua," & vbCrLf & vbCrLf & _
"Sistemul automat de monitorizare stocuri a detectat " & nrAlerte & _
" produse cu stoc sub nivelul minim." & vbCrLf & vbCrLf & _
"Lista detaliată este atașată în PDF." & vbCrLf & vbCrLf & _
"Excel Group Stoc Monitor"
.Attachments.Add caleaPDF
.Display ' sau .Send pentru trimitere directă
End With
End Sub
Gestionarea erorilor: codul profesionist
Sub ProceduraRobusta()
On Error GoTo GestionareEroare
' codul tău aici
GoTo Sfarsit
GestionareEroare:
Dim mesaj As String
mesaj = "Eroare " & Err.Number & ": " & Err.Description & vbCrLf & _
"Linia: " & Erl & vbCrLf & _
"Procedura: ProceduraRobusta"
' Loghezi eroarea într-o foaie sau fișier
LogEroare mesaj
MsgBox mesaj, vbCritical, "Eroare"
Resume Sfarsit
Sfarsit:
' Cleanup: restaurezi întotdeauna setările
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
End Sub
Sub LogEroare(mesaj As String)
Dim wsLog As Worksheet
Set wsLog = GetOrCreateSheet(ThisWorkbook, "Log_Erori")
Dim rnd As Long
rnd = LastRow(wsLog) + 1
wsLog.Cells(rnd, 1).Value = Now
wsLog.Cells(rnd, 2).Value = mesaj
End Sub
Concluzie
VBA avansat transformă Excel dintr-un instrument de calcul într-un sistem de automatizare complet. Cu 100-200 de linii de cod bine scrise, automatizezi munci care durau ore — și o faci corect, de fiecare dată.
La Excel Group scriem și implementăm soluții VBA pentru firme din România și Moldova — de la rapoarte automate la sisteme complete de procesare date. Contactează-ne.
Întrebări frecvente
VBA mai e relevant în 2026, cu Office Scripts și Python în Excel?
Da — VBA rămâne cel mai complet instrument pentru automatizare Excel locală, integrare cu aplicații Windows (Outlook, Word, Access) și compatibilitate cu versiuni vechi. Office Scripts e mai bun pentru automatizare cloud/SharePoint.
Codul VBA se poate proteja de vizualizare?
Da — din VBA Editor: Tools → VBAProject Properties → Protection → Lock project for viewing + parolă. Nu e criptare militară, dar descurajează modificările accidentale.
Pot apela API-uri externe din VBA?
Da — cu obiectul XMLHTTP sau WinHttp.WinHttpRequest. Poți face GET/POST la orice API REST și procesa răspunsul JSON (manual cu funcții de parsing sau cu un parser JSON VBA open-source).

