Chuyên đề giải đáp những thắc mắc về code VBA

Nguyễn Hoàng Oanh Thơ

Thành viên tích cực
Tham gia ngày
5 Tháng mười một 2015
Bài viết
1,146
Được thích
495
Điểm
235
Nơi ở
Hà Nội
Tôi chưa từng biết Sub Mẹ Sub, Con viết như Bác @VetMini gợi ý.
Làm liều thử 1 bài xem, nếu có người sửa sai thì sẽ là 1 cách học "Chiêu" mới.
PHP:
Public Sub Cha()
Dim I As Long, J As Long, X As Long
    For I = 1 To 10
        X = X + 1           'Cong Viec 1- Lam gi do'
        For J = 1 To 10    
            Cells(X, J) = "GPE" & Format(I, "000")
        Next J
        X = X + 1
        GoSub Con           'Goi Sub Con'
            X = X + 1       'Cong Viec 2 - Lam gi do'
            For J = 1 To 10
                Cells(X, J) = "Hic!" & Format(I, "000")
            Next J
        X = X + 1
        GoSub Con           'Goi Sub Con'
    Next I
    Exit Sub    'Thoat Sub Cha'
Con:            'Sub Con Lam gi do'
        For J = 1 To 10
            Cells(X, J) = "Con" & " - " & Format(J, "000")
        Next J
Return  'Quay lai dong lenh sau GoSub'
End Sub
Con cảm ơn Thầy đã chỉ dẫn,con sẽ nghiên cứu tìm hiểu để áp dụng ạ.
 

Ba Tê

Gội Rồi Mới Cạo
Tham gia ngày
5 Tháng năm 2009
Bài viết
11,487
Được thích
16,395
Điểm
1,860
Tuổi
61
Nơi ở
An Giang

SA_DQ

/(hông là gì!
Thành viên danh dự
Tham gia ngày
8 Tháng sáu 2006
Bài viết
11,397
Được thích
17,305
Điểm
1,860
Sub locdulieu()
Sheets(1).Range("A1" & lastcolumn & lastRow).AutoFilter Field:=3, Criteria1:="活动优惠"
lastRow = Range("A85536").End(xlUp).Row
If Sheets("活动优惠").Cells(1, 1) = "" Then
Range("A1:I" & lastRow).Select
Selection.Copy
Sheets("活动优惠").Select
Range("A1").Select
ActiveSheet.Paste
Columns("A:H").Select
Columns("A:H").EntireColumn.AutoFit
Else
Range("A2:I" & lastRow).Select
Selection.Copy
Sheets("活动优惠").Select
lastRow = Range("A85536").End(xlUp).Row
Range("A" & lastRow + 1).Select
ActiveSheet.Paste
Columns("A:H").Select
Columns("A:H").EntireColumn.AutoFit
End If
astRow = Range("A85536").End(xlUp).Row
Range("A" & lastRow + 1).Select
Sheets(1).Select
Trong code có đoạn nào nói về đường lưỡi bò không vậy bạn?
 

Cu Tồ

Thành viên mới
Tham gia ngày
6 Tháng năm 2020
Bài viết
39
Được thích
7
Điểm
15
mong mn giúp đỡ
Bài đã được tự động gộp:

Sub locdulieu()

Sheets(1).Range("A1" & lastcolumn & lastRow).AutoFilter Field:=3, Criteria1:="tangthuong"
lastRow = Range("A85536").End(xlUp).Row
If Sheets("tangthuong").Cells(1, 1) = "" Then
Range("A1:I" & lastRow).Select
Selection.Copy
Sheets("tangthuong").Select
Range("A1").Select
ActiveSheet.Paste
Columns("A:H").Select
Columns("A:H").EntireColumn.AutoFit
Else

Range("A2:I" & lastRow).Select
Selection.Copy
Sheets("tangthuong").Select
lastRow = Range("A85536").End(xlUp).Row
Range("A" & lastRow + 1).Select
ActiveSheet.Paste
Columns("A:H").Select
Columns("A:H").EntireColumn.AutoFit
End If
lastRow = Range("A85536").End(xlUp).Row
Range("A" & lastRow + 1).Select
Sheets(1).Select

mọi người cho hỏi là trong đoạn code này dùng AutoFilter để lọc dữ liệu nhưng khi lọc không có kêt quả nó lại copy ngay dòng tiêu đề để paste ,vậy mn cho hỏi là code sửa ntn để khi autofilter mà không ra kết quả như thế này View attachment 237539 thì sẽ không copy nữa mà thực hiện lệnh tiếp theo của đoạn code sau ah?
mong mn giúp đỡ
 

VetMini

Chuyên gia GPE
Tham gia ngày
21 Tháng mười hai 2012
Bài viết
8,917
Được thích
10,441
Điểm
1,560
Tôi chưa từng biết Sub Mẹ Sub, Con viết như Bác @VetMini gợi ý.
Làm liều thử 1 bài xem, nếu có người sửa sai thì sẽ là 1 cách học "Chiêu" mới.
PHP:
Public Sub Cha()
Dim I As Long, J As Long, X As Long
    For I = 1 To 10
        X = X + 1           'Cong Viec 1- Lam gi do'
        For J = 1 To 10  
            Cells(X, J) = "GPE" & Format(I, "000")
        Next J
        X = X + 1
        GoSub Con           'Goi Sub Con'
            X = X + 1       'Cong Viec 2 - Lam gi do'
            For J = 1 To 10
                Cells(X, J) = "Hic!" & Format(I, "000")
            Next J
        X = X + 1
        GoSub Con           'Goi Sub Con'
    Next I
    Exit Sub    'Thoat Sub Cha'
Con:            'Sub Con Lam gi do'
        For J = 1 To 10
            Cells(X, J) = "Con" & " - " & Format(J, "000")
        Next J
Return  'Quay lai dong lenh sau GoSub'
End Sub
Mục đích chính của GoSub là để tránh lặp lại code.
Nếu công việc 1 và công việc 2 gần giống nhau thì bạn cũng có thể tạo một sub con nữa.
Lưu ý rằng hai công việc có các lệnh giống nhau nhưng thong số khác nhau cho nên ta phải dùng một biến để thực hiện thông số này (biến danDau trong code).

PHP:
Public Sub Cha()
Dim I As Long, J As Long, X As Long
DIM daDau As String
    For I = 1 To 10
      ' công việc 1, làm gì đó '
      danDau = "GPE"
      GoSub Con_Ruot
      danDau = "Con - "
      GoSub Con_Ghe
      ' công việc 2, làm gì đó '
      danDau = "Hic!"
      GoSub Con_Ruot
      danDau = "Con - "
      GoSub Con_Ghe
    Next I
    Exit Sub    'Thoat Sub Cha'

Con_Ruot:
        ' công việc 3, làm gì đó '
        ' sau khi hoàn tất công việc 3, gọi sub Con_Ghe để thực hiện việc tăng X và ghi trị vào 10 cells '
        GoSub Con_Ghe
Return

Con_Ghe:            'Sub Con Lam gi do'
        X = X + 1
        For J = 1 To 10
            Cells(X, J) = danDau & Format(J, "000")
        Next J
Return
End Sub
Code trên tôi cố tình cho thấy Con_Ruot có thể gọi Con_Ghe vô tư.
(ngược lại, Con_Ghe có thể gọi Con_Ruot nếu muốn)
 

ppc0312

whom?
Tham gia ngày
2 Tháng tư 2008
Bài viết
619
Được thích
315
Điểm
735
Mục đích chính của GoSub là để tránh lặp lại code.
Nếu công việc 1 và công việc 2 gần giống nhau thì bạn cũng có thể tạo một sub con nữa.
Lưu ý rằng hai công việc có các lệnh giống nhau nhưng thong số khác nhau cho nên ta phải dùng một biến để thực hiện thông số này (biến danDau trong code).

PHP:
Public Sub Cha()
Dim I As Long, J As Long, X As Long
DIM daDau As String
    For I = 1 To 10
      ' công việc 1, làm gì đó
      danDau = "GPE"
      GoSub Con_Ruot
      danDau = "Con - "
      GoSub Con_Ghe
      ' công việc 2, làm gì đó
      danDau = "Hic!"
      GoSub Con_Ruot
      danDau = "Con - "
      GoSub Con_Ghe
    Next I
    Exit Sub    'Thoat Sub Cha'

Con_Ruot:
        ' công việc 3, làm gì đó
        ' sau khi hoàn tất công việc 3, gọi sub Con_Ghe để thực hiện việc tăng X và ghi trị vào 10 cells
        GoSub Con_Ghe           'Goi Sub Con'
Return

Con_Ghe:            'Sub Con Lam gi do'
        X = X + 1
        For J = 1 To 10
            Cells(X, J) = danDau & Format(J, "000")
        Next J
Return
End Sub
Code trên tôi cố tình cho thấy Con_Ruot có thể gọi Con_Ghe vô tư.
(ngược lại, Con_Ghe có thể gọi Con_Ruot nếu muốn)
Bác cứ phức tạp vấn đề, cứ chia ra sub con riêng cho nhanh, và như thế thỏa mãi số con mà không rối... còn truyền biến thì độc lập hay phụ thuộc cũng tùy thích

GoSub đúng như bác nói người ta hạn chế dùng, nếu dùng dùng cho trường hợp đặc biệt hay vui mà thôi
 

VetMini

Chuyên gia GPE
Tham gia ngày
21 Tháng mười hai 2012
Bài viết
8,917
Được thích
10,441
Điểm
1,560
Bác cứ phức tạp vấn đề, cứ chia ra sub con riêng cho nhanh, và như thế thỏa mãi số con mà không rối... còn truyền biến thì độc lập hay phụ thuộc cũng tùy thích

GoSub đúng như bác nói người ta hạn chế dùng, nếu dùng dùng cho trường hợp đặc biệt hay vui mà thôi
Sẵn đề tài ở bài #2724, Tôi chỉ dẫn dắt về một kỹ thuật code mà nó gần sát nhất với yêu cầu củab bài.

Vì là dẫn dắt cho nên tôi thêm hoa lá cành cho nó hơi phức tạp một chút. Chứ đơn giản quá thì chả có mấy để học.

Trước khi vào, tôi cũng có nói rằng Go<...> là kỹ thuật phi cấu trúc (non-structred). Chính bản thân tôi cũng không thích dùng.
Nhất là khi Sub con dựa vào nhiều thông số và thay đổi nhiều biến, rất khó kiểm soát và debug.

Nhưng nếu tôn chỉ của diễn đàn này là tốc độ code thì Go<...> là con đường đáng bỏ tâm nghiên cứu.
Code phi cấu trúc thường chạy nhanh hơn. GoSub là lệnh rẽ nhánh lập tức, VBA chỉ phải nhét ngăn xếp cái địa chỉ để 'Return'. Nếu gọi hàm riêng biệt thì VBA phải nhét ngăn xếp nhiều thứ nữa. Đồng thời, vì không phải dùng ngăn xếp nhiều nên dệ quy cũng lâu bị tràn ngăn xếp hơn.
 

Nguyễn Hoàng Oanh Thơ

Thành viên tích cực
Tham gia ngày
5 Tháng mười một 2015
Bài viết
1,146
Được thích
495
Điểm
235
Nơi ở
Hà Nội
Xin chào tất cả mọi mọi người,
OT có một vấn đề như sau:
Làm thế nào để từ bảng 1 chuyển sang bảng 2 thay đổi định dạng.
Cột A -> F (Long-> String)
Cột B -> G (Stirng -> Long)
OT đã code một đoạn sau để thử nhưng không được:
Mã:
Option Explicit

Sub Test_String_And_Long()
    Dim Vao(), Ra(), I As Long
    Vao = Sheet1.Range("A3:C12").Value
    ReDim Ra(1 To UBound(Vao, 1), 1 To UBound(Vao, 2))
    For I = 1 To UBound(Vao, 1)
       Ra(I, 1) = CStr(Vao(I, 1))
       Ra(I, 2) = CLng(Vao(I, 2))
       Ra(I, 3) = Ra(I, 1) + Ra(I, 2)
    Next I
    Sheet1.Range("F3").Resize(UBound(Ra, 1), UBound(Ra, 2)) = Ra
End Sub
Nhờ các Bạn chỉ dẫn cho cách làm ạ.

Untitled.jpg
 

File đính kèm

Lần chỉnh sửa cuối:

Nguyễn Hoàng Oanh Thơ

Thành viên tích cực
Tham gia ngày
5 Tháng mười một 2015
Bài viết
1,146
Được thích
495
Điểm
235
Nơi ở
Hà Nội
Xin chào tất cả mọi mọi người,
OT có một vấn đề như sau:

OT đã code một đoạn sau để thử nhưng không được:
Mã:
Option Explicit

Sub Test_String_And_Long()
    Dim Vao(), Ra(), I As Long
    Vao = Sheet1.Range("A3:C12").Value
    ReDim Ra(1 To UBound(Vao, 1), 1 To UBound(Vao, 2))
    For I = 1 To UBound(Vao, 1)
       Ra(I, 1) = CStr(Vao(I, 1))
       Ra(I, 2) = CLng(Vao(I, 2))
       Ra(I, 3) = Ra(I, 1) + Ra(I, 2)
    Next I
    Sheet1.Range("F3").Resize(UBound(Ra, 1), UBound(Ra, 2)) = Ra
End Sub
Nhờ các Bạn chỉ dẫn cho cách làm ạ.

View attachment 237625
Hình như cả CStr & CLng đều không có tác dụng trong trường hợp này ạ?
Nếu làm như thế này thì lại được:
Mã:
Option Explicit

Sub Test_String_And_Long()
    Dim Vao(), Ra(), I As Long
    Vao = Sheet1.Range("A3:C12").Value
    ReDim Ra(1 To UBound(Vao, 1), 1 To UBound(Vao, 2))
    For I = 1 To UBound(Vao, 1)
       Ra(I, 1) = "'" & Vao(I, 1)
       Ra(I, 2) = Vao(I, 2)
       Ra(I, 3) = "=SUM(RC[-2]:RC[-1])"
    Next I
    Sheet1.Range("F3").Resize(UBound(Ra, 1), UBound(Ra, 2)) = Ra
End Sub
Có cách làm khác không ạ?
 

CHAOQUAY

Thành viên tích cực
Tham gia ngày
24 Tháng tám 2018
Bài viết
1,084
Được thích
1,132
Điểm
360
Hình như cả CStr & CLng đều không có tác dụng trong trường hợp này ạ?
Nếu làm như thế này thì lại được:
Mã:
Option Explicit

Sub Test_String_And_Long()
    Dim Vao(), Ra(), I As Long
    Vao = Sheet1.Range("A3:C12").Value
    ReDim Ra(1 To UBound(Vao, 1), 1 To UBound(Vao, 2))
    For I = 1 To UBound(Vao, 1)
       Ra(I, 1) = "'" & Vao(I, 1)
       Ra(I, 2) = Vao(I, 2)
       Ra(I, 3) = "=SUM(RC[-2]:RC[-1])"
    Next I
    Sheet1.Range("F3").Resize(UBound(Ra, 1), UBound(Ra, 2)) = Ra
End Sub
Có cách làm khác không ạ?
Chưa thử nhưng dùng lệnh clear xóa vùng ("F3").resize... trước khi điền xuống sheet xem.
 

Nguyễn Hoàng Oanh Thơ

Thành viên tích cực
Tham gia ngày
5 Tháng mười một 2015
Bài viết
1,146
Được thích
495
Điểm
235
Nơi ở
Hà Nội
Chưa thử nhưng dùng lệnh clear xóa vùng ("F3").resize... trước khi điền xuống sheet xem.
Xin chào CHAOQUAY
Dạ thì kết quả nó trả về giống Bảng 2 như ảnh trong bài 2489 theo ý muốn của OT đó Bạn.
Vấn đề là ở đây OT muốn hỏi xem có cách nào chuyển kiểu số sang kiểu text hoặc ngược lại trong mảng không ạ, nhưng mà với trường hợp của OT hình như cứ đưa số định dạng text vào mảng là nó chuyển thành số hay sao ấy,, híc!
'-------------------------------------
Ah nó có dấu ' ở đầu Bạn ơi...
 
Lần chỉnh sửa cuối:

CHAOQUAY

Thành viên tích cực
Tham gia ngày
24 Tháng tám 2018
Bài viết
1,084
Được thích
1,132
Điểm
360
Xin chào CHAOQUAY
Dạ thì kết quả nó trả về giống Bảng 2 như ảnh trong bài 2489 theo ý muốn của OT đó Bạn.
Vấn đề là ở đây OT muốn hỏi xem có cách nào chuyển kiểu số sang kiểu text hoặc ngược lại trong mảng không ạ, nhưng mà với trường hợp của OT hình như cứ đưa số định dạng text vào mảng là nó chuyển thành số hay sao ấy,, híc!
'-------------------------------------
Ah nó có dấu ' ở đầu Bạn ơi...
bạn thử khai báo
dim Ra() as string xem
 

Nguyễn Hoàng Oanh Thơ

Thành viên tích cực
Tham gia ngày
5 Tháng mười một 2015
Bài viết
1,146
Được thích
495
Điểm
235
Nơi ở
Hà Nội
bạn thử khai báo
dim Ra() as string xem
Dạ , nếu làm thế này thì cả mảng Ra thàn chuỗi hết ạ, kết quả trả về không chỉ riêng cột F là chuỗi mà cả G & H cũng thành chuỗi theo luôn.
Có cách nào vẫn xử lý trong cùng mảng được không Bạn?
 

CHAOQUAY

Thành viên tích cực
Tham gia ngày
24 Tháng tám 2018
Bài viết
1,084
Được thích
1,132
Điểm
360
Dạ , nếu làm thế này thì cả mảng Ra thàn chuỗi hết ạ, kết quả trả về không chỉ riêng cột F là chuỗi mà cả G & H cũng thành chuỗi theo luôn.
Có cách nào vẫn xử lý trong cùng mảng được không Bạn?
Thường là mảng chỉ khai báo theo một kiểu, nếu vậy bạn tách mảng Ra() thành 1 vài mảng có kiểu khác nhau xem sao.
Bài đã được tự động gộp:

Xóa format của vùng điền kết quả trong sheet cũng cần quan tâm đó bạn
 

Hau151978

Thành viên tích cực
Tham gia ngày
19 Tháng mười 2011
Bài viết
1,346
Được thích
1,235
Điểm
560
Dạ , nếu làm thế này thì cả mảng Ra thàn chuỗi hết ạ, kết quả trả về không chỉ riêng cột F là chuỗi mà cả G & H cũng thành chuỗi theo luôn.
Có cách nào vẫn xử lý trong cùng mảng được không Bạn?
Tự động chuyển đổi kiểu là một đặc điểm của VBA. Khi bạn đã biết 1 cột là text, 1 cột là number thì tốt nhất đừng cộng vào nhau để tránh ra kết quả không mong muốn. Phép tính trên sheet và VBA cũng có thể khác nhau, chẳng hạn trong VBA "1"+"1"="11" (bạn nhập ?"1"+"1" trong cửa sổ immediate sẽ thấy kết quả là 11) nhưng trên sheet thì "1"+"1"=2 (bạn nhập công thức A1 ="1"+"1" kết quả là 2). Do đó trước khi làm phép tính thì bạn cần tự quyết định các toán hạng trong phép tính là số hay chuỗi và đừng mong chờ VBA chuyển đổi đúng ý mình. Nếu trong VBA mà ta cần cộng nhiều ô trên sheet và chỉ cộng các số, bỏ qua text thì có thể dùng Application.Sum để tính.
 

ongke0711

Thành viên tiêu biểu
Tham gia ngày
7 Tháng chín 2006
Bài viết
546
Được thích
605
Điểm
860
Nơi ở
HCM
Mã:
Option Explicit

Sub Test_String_And_Long()
    Dim Vao(), Ra(), I As Long
    Vao = Sheet1.Range("A3:C12").Value
    ReDim Ra(1 To UBound(Vao, 1), 1 To UBound(Vao, 2))
    For I = 1 To UBound(Vao, 1)
       Ra(I, 1) = CStr(Vao(I, 1))
       Ra(I, 2) = CLng(Vao(I, 2))
       Ra(I, 3) = Ra(I, 1) + Ra(I, 2)
    Next I
    Sheet1.Range("F3").Resize(UBound(Ra, 1), UBound(Ra, 2)) = Ra
End Sub
Thực ra là theo cách trên đổi kiểu dữ liệu trong mảng là được nhưng khi gán xuống Sheet thì không như ý. Vấn đề này thì anh chưa biết nguyên nhân của nó.
Đối với code trên anh nghĩ không cần tạo thêm mảng Ra(), chuyển đổi luôn trong mảng Vao() cũng được (thay chữ "Ra" -> "Vao" xem thử) . Anh test với Typename thì thấy ra đúng kiểu dữ liệu cần chuyển, chỉ gán xuống Sheet là lỗi.
Chờ các bạn nào biết giải thích thêm để học hỏi vụ này.
 

Nguyễn Hoàng Oanh Thơ

Thành viên tích cực
Tham gia ngày
5 Tháng mười một 2015
Bài viết
1,146
Được thích
495
Điểm
235
Nơi ở
Hà Nội
Thực ra là theo cách trên đổi kiểu dữ liệu trong mảng là được nhưng khi gán xuống Sheet thì không như ý. Vấn đề này thì anh chưa biết nguyên nhân của nó.
Đối với code trên anh nghĩ không cần tạo thêm mảng Ra(), chuyển đổi luôn trong mảng Vao() cũng được (thay chữ "Ra" -> "Vao" xem thử) . Anh test với Typename thì thấy ra đúng kiểu dữ liệu cần chuyển, chỉ gán xuống Sheet là lỗi.
Chờ các bạn nào biết giải thích thêm để học hỏi vụ này.
Đúng rồi anh, trong mảng thì không vấn đề gì nhưng khi đưa xuống sheet thì thay đổi do đó phải thêm dòng code: NumberFormat trước khi đưa dữ liệu xuống sheet anh ạ.
OT cũng đang chờ một giải pháp khác ạ.
Cảm ơn anh đã thông tin ạ
 

HieuCD

Chuyên gia GPE
Tham gia ngày
14 Tháng chín 2010
Bài viết
6,770
Được thích
13,002
Điểm
1,560
Xin chào tất cả mọi mọi người,
OT có một vấn đề như sau:

OT đã code một đoạn sau để thử nhưng không được:
Mã:
Option Explicit

Sub Test_String_And_Long()
    Dim Vao(), Ra(), I As Long
    Vao = Sheet1.Range("A3:C12").Value
    ReDim Ra(1 To UBound(Vao, 1), 1 To UBound(Vao, 2))
    For I = 1 To UBound(Vao, 1)
       Ra(I, 1) = CStr(Vao(I, 1))
       Ra(I, 2) = CLng(Vao(I, 2))
       Ra(I, 3) = Ra(I, 1) + Ra(I, 2)
    Next I
    Sheet1.Range("F3").Resize(UBound(Ra, 1), UBound(Ra, 2)) = Ra
End Sub
Nhờ các Bạn chỉ dẫn cho cách làm ạ.

View attachment 237625
Khai báo 1 mảng vào 2 mảng Ra
Dim Vao(), Ra() as string, Ra2() as long
Hoặc
Dim Vao(), Ra() as string, Ra2()
 
Top Bottom