Lỗi Và Thời Điểm Xuất Hiện
Bạn đang chạy một macro VBA — duyệt qua 50.000 hàng, tính tổng doanh số, hoặc theo dõi một bộ đếm vượt quá con số 33.000 — thì Excel ném cho bạn thông báo này:
Run-time error '6': Overflow
Macro dừng lại ngay lập tức. VBA Editor mở ra và tô vàng một dòng code. Đó chính là nơi VBA cố nhét một con số vào một "chiếc hộp" quá nhỏ để chứa nó.
Mỗi biến VBA có một phạm vi số cố định. Đẩy một giá trị vượt ngoài phạm vi đó là bạn nhận ngay lỗi Overflow. Chín trên mười trường hợp, nguyên nhân là một biến Integer đang làm một công việc cần đến Long.
Nguyên Nhân Gốc Rễ
Mỗi kiểu dữ liệu VBA chỉ chứa được giá trị trong một phạm vi nhất định:
- Integer: –32.768 đến 32.767
- Long: –2.147.483.648 đến 2.147.483.647
- Single: ±3,4 × 1038 (độ chính xác hạn chế)
- Double: ±1,8 × 10308
- Byte: 0 đến 255
- Currency: –922.337.203.685.477,5808 đến 922.337.203.685.477,5807
Giới hạn 32.767 của Integer chính là con số hay gây rắc rối. Excel đã hỗ trợ tới 1.048.576 hàng kể từ Excel 2007. Khai báo một Integer làm biến đếm hàng và VBA sẽ sập ngay khi bạn đến hàng 32.768. Trang tính có tới một triệu hàng, còn bộ đếm của bạn chỉ đi được đến ba mươi hai nghìn.
Bước 1 — Xác Định Dòng Lỗi Chính Xác
Đừng nhấn End khi hộp thoại xuất hiện. Hãy nhấn Debug thay vào đó. VBA Editor sẽ mở ra và tô vàng dòng lệnh bị lỗi — đó chính xác là nơi xảy ra tràn số.
Ba dạng lỗi phổ biến nhất:
' Biến đếm khai báo là Integer, trang tính có hơn 32.767 hàng
Dim i As Integer
For i = 1 To 100000 ' Crashes at 32,768
' ...
Next i
' Kết quả phép tính vượt quá phạm vi Integer
Dim result As Integer
result = 200 * 200 ' 40,000 > 32,767 → Overflow
' Số hàng cuối cùng trả về 50.000+ nhưng lưu trong Integer
Dim rowCount As Integer
rowCount = Cells(Rows.Count, 1).End(xlUp).Row
Bước 2 — Xác Định Biến Bị Tràn
Di chuột qua bất kỳ biến nào trên dòng được tô vàng — tooltip sẽ hiện giá trị hiện tại của nó. Vẫn chưa rõ? Thêm một lệnh Debug.Print vào dòng trước chỗ bị lỗi:
Debug.Print "Value before overflow: " & yourVariable
Mở cửa sổ Immediate bằng Ctrl+G, rồi chạy lại macro. Giá trị được in ra sẽ cho bạn biết chính xác con số nào đã gây ra lỗi.
Bước 3 — Sửa Kiểu Dữ Liệu
Thay Integer Bằng Long
Thay đổi đơn giản này giải quyết khoảng 80% lỗi Overflow. Bất kỳ biến nào dùng để đếm hàng, lưu ID, hoặc tích lũy tổng có thể vượt quá 32.767 đều nên dùng Long:
' Trước — sập khi vượt hàng 32.767
Dim i As Integer
For i = 1 To lastRow
' process row
Next i
' Sau — xử lý đủ 1.048.576 hàng mà không có vấn đề gì
Dim i As Long
For i = 1 To lastRow
' process row
Next i
Sửa Phép Tính Gây Tràn Số
Có một bẫy khá tinh vi ở đây. VBA tính toán biểu thức dựa trên kiểu dữ liệu của các toán hạng — không phải kiểu của biến nhận kết quả. Khai báo result As Long sẽ không giúp được gì nếu bạn nhân hai số nguyên kiểu Integer. Biểu thức đã bị tràn trước khi lệnh gán được thực thi.
' Bẫy: biểu thức tràn trước khi gán
Dim result As Long
result = 200 * 200 ' 200 và 200 là Integer → Integer * Integer → Overflow
' Cách 1: Hậu tố Long literal
result = 200& * 200
' Cách 2: Ép kiểu tường minh
result = CLng(200) * 200
' Cách 3: Khai báo toán hạng là Long
Dim a As Long, b As Long
a = 200 : b = 200
result = a * b
Sửa Tràn Số Single/Double
Các con số cực lớn hoặc tính toán khoa học có thể vượt quá giới hạn ~2,1 tỷ của Long. Hãy chuyển sang Double:
Dim bigNum As Double
bigNum = 3000000000# * 1500 ' # suffix forces Double literal
Sửa Tràn Số Byte
Byte chỉ chứa giá trị 0–255. Gán mã lỗi –1 vào một biến Byte là bạn nhận ngay lỗi Overflow:
' Trước
Dim status As Byte
status = someFunction() ' Returns -1 on error → Overflow
' Sau
Dim status As Integer
Ví Dụ Đã Sửa Hoàn Chỉnh
Một tình huống thực tế: tính tổng một cột trên tất cả các hàng đang dùng. Phiên bản lỗi chạy tốt trên file thử nghiệm nhỏ — rồi âm thầm sập trên môi trường thực khi dữ liệu vượt quá 32.767 hàng.
' LỖI — tràn số trên trang tính có hơn 32.767 hàng
Sub ProcessData_Broken()
Dim i As Integer
Dim total As Integer
Dim lastRow As Integer
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
total = total + Cells(i, 2).Value
Next i
MsgBox "Total: " & total
End Sub
' ĐÃ SỬA
Sub ProcessData_Fixed()
Dim i As Long
Dim total As Double ' Double cho tổng có thể tăng lớn
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
total = total + CDbl(Cells(i, 2).Value)
Next i
MsgBox "Total: " & total
End Sub
Kiểm Tra Sau Khi Sửa
- Nhấn F5 để chạy. Không có hộp thoại lỗi nghĩa là lỗi tràn số đã được xử lý.
- In số hàng ra để xác nhận các phạm vi lớn được xử lý đúng:
Debug.Print "Processing " & lastRow & " rows". - Kiểm thử với trang tính có hơn 32.767 hàng nếu dữ liệu của bạn có thể đạt đến con số đó.
- Chạy từng bước với F8 và quan sát cửa sổ Locals (View → Locals Window) để phát hiện bất kỳ biến nào đang tiệm cận giới hạn kiểu dữ liệu của nó.
Thói Quen Phòng Ngừa Về Sau
- Mặc định dùng Long, không dùng Integer:
Longchiếm 4 byte so với 2 byte củaInteger, nhưng các bộ vi xử lý hiện đại xử lý số nguyên 32-bit một cách tự nhiên — không có sự khác biệt hiệu năng đáng kể. Bạn loại bỏ được giới hạn phạm vi của Integer mà không phải đánh đổi bất cứ điều gì. - Dùng Option Explicit: Đặt
Option Explicitở đầu mỗi module. Nó bắt buộc khai báo biến, giúp bạn quyết định kiểu dữ liệu ngay từ đầu thay vì để chúng thành lỗi runtime. - Chú ý đến các số nguyên kiểu literal:
200mặc định làIntegertrong VBA. Dùng hậu tố kiểu để rõ ràng hơn:200&cho Long,200#cho Double. - Kiểm tra dữ liệu từ bên ngoài: Nếu giá trị ô tính điều khiển một lệnh gán, hãy chạy
IsNumeric()trước và kiểm tra phạm vi hợp lệ trước khi lưu vào biến có kiểu dữ liệu cụ thể.

