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

Liên hệ QC

maytinhvp01

Thành viên thường trực
Tham gia
27/7/13
Bài viết
390
Được thích
179
Mình muốn nhờ giải thich câu lệnh " If Ran.Cells(d, c) > max Then max = Ran.Cells(d, c) "
trong ví du:
Public Function LonNhat(Ran As Range)
Dim max As Double, v As Integer, d As Integer, c As Integer
max = Ran.Cells(1, 1)
For d = 1 To Ran.Rows.Count
For c = 1 To Ran.Columns.Count
If Ran.Cells(d, c) > max Then max = Ran.Cells(d, c)
Next c
Next d
v = Tim(max, Ran)
LonNhat = max
End Function
-------------------------------------------------------
[INFO1]Thông báo:
Vì topic này:
http://www.giaiphapexcel.com/forum/...ải-thích-các-code-đề-nghị-các-bạn-gửi-vào-đây
đã quá dài nên BQT đóng lại.
Nay tôi mở topic mới với cùng chủ đề: GIẢI THÍCH NHỮNG THẮC MẮC VỀ CODE
Các bạn nếu có nhu cầu giải thích code, vui lòng post tại đây nhé
NDU96081631

[/INFO1]
 
Chỉnh sửa lần cuối bởi điều hành viên:
Cảm ơn bác Siwtom,
Con muốn đưa dữ liệu từ 2 file lấy được trong filenames:
Lấy dữ liệu sheets(1) file vị trí 1 (file chọn trước) đưa vào sheet1 của file Laydulieu.xlsm
Lấy dữ liệu sheets(1) file vị trí 2 (file chọn sau) đưa vào sheet2 của file Laydulieu.xlsm
Laydulieu.xlsm là file chứa code trên "sub GetImportValues" ạ.
Con chưa biết cách làm tiếp bước này, bác chỉ giúp con ạ.
Việc xử lý 2 tập tin thì HeSanbi đã hướng dẫn bạn rồi còn gì.
 
Upvote 0
Code Copy từ Sheet này sang Sheet khác
Các bạn giúp code hoặc chỉ đường Link (nếu có) như sau:
Trong 1 file, em muốn copy từ Sheet A sang Sheet B như sau:
* Sheet A: tại cột D, E, F có dữ liệu từ dòng thứ 5 trở xuống
1/Em muốn copy số liệu cột D, E và sang sheet B dán tại cột F, G
2/Em muốn copy số liệu cột F và sang sheet B dán tại cột I
Bắt đầu dán từ dòng số 9 (Xem file đính kèm)Xin cảm ơn
 

File đính kèm

  • Copy-dan.xlsx
    9.1 KB · Đọc: 1
Upvote 0
@Nguyễn Hoàng Oanh Thơ
Lời khuyên vẫn nên vận dụng cái "hiện đại".
Nghe OT nói đang học VBA không biết học tới đâu rồi.
Hôm trước thấy trả lời bài viết rất tốt. Sao nay lại chững bước với vấn đề tương tự thế này

Code dưới gọn gàn hơn Code tôi gợi ý lúc trước
PHP:
Function GetFileFullname(FolderPath As String, Optional sDesc As String = "Excel", _
                                             Optional sFilter As String = "*.xls") As Variant
  GetFileFullname = Array()
  Dim Arr(), k, it
  With Application.FileDialog(msoFileDialogOpen)
    .ButtonName = "&Open" 'Nút chỉ thị
    .initialFilename = FolderPath 'Đi đến đường dẫn cho trước
    '.Filters.Delete(1) '
    .Filters.Clear 'Xóa gợi ý các loại tệp mở rộng
    .Filters.Add sDesc, sFilter 'Bắt đầu thêm lại Gợi ý - Mặc định
    .Filters.Add "All File", "*.*" 'Thêm 1 Gợi ý nữa
    .Title = "File Open" 'Tiêu đề
    .InitialView = msoFileDialogViewDetails 'Kiểu sắp xếp để xem
    .AllowMultiSelect = True 'Cho phép chọn nhiều tệp
    If .show = -1 Then
      For Each it In .SelectedItems
        ReDim Preserve Arr(k): Arr(k) = it
        k = k + 1
      Next it
      GetFileFullname = Arr
    End If
  End With
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Xin chào các bạn,
Oanh Thơ(OT) có sưu tầm một câu lệnh như sau để lấy dữ liệu bằng phương pháp GetOpenFilename.

Mã:
Sub GetImportValues()
'https://stackoverflow.com/questions/22248800/vba-how-to-import-values-from-several-excel-files-selected-by-users-via-dialog
    Dim filenames, f
    Dim myMsg As String
    Dim wb As Workbook
    Dim lastrow As Long
    'Get the filename
    filenames = Application.GetOpenFilename(FileFilter:="Excel VBA files (*.xls*), *.xls*", _
                                            FilterIndex:=1, _
                                            Title:="pls select the excel files to Import", _
                                            MultiSelect:=True)
    If IsArray(filenames) Then
        myMsg = "You selected:" & vbNewLine
        'Display full path and name of the files
        For Each f In filenames
            myMsg = myMsg & f & vbNewLine
        Next f
        MsgBox myMsg
    Else
        MsgBox "No excel file was selected."
        Exit Sub
    End If

    For Each f In filenames
        Set wb = Workbooks.Open(f)

        With ThisWorkbook.Sheets("Results")
            'determine last non empty row in column A sheet "Result" to past result
            lastrow = Application.Max(3, .Cells(.Rows.Count, "A").End(xlUp).Row + 1)
            .Range("A" & lastrow).Value = wb.Sheets("Sheet1").Range("I3").Value
        End With

        wb.Close SaveChanges:=False
        Set wb = Nothing
    Next f
End Sub

-------------
Mong muốn của OT làm sao chỉ chọn được 2 tập tin muốn lấy (2 tập tin này để trong cùng một thư mục, nhưng khác với thư mục chứa tập tin chạy code "ThisWorkbook.Name")
Và mỗi tập tin được chọn sẽ đưa dữ liệu vào sheet khác nhau của tập tin chạy code "ThisWorkbook.Name".

Ví dụ:
Khi chạy code hiện cửa sổ tìm đến thư mục XYZ
lựa chọn 2 tập tin A.xls và B.xls nằm trong cùng một thư mục : XYZ
Tập tin A.xls sẽ đổ dữ liệu vào ThisWorkbook.Sheets("Results1").range("A1")
Tập tin B.xls sẽ đổ dữ liệu vào ThisWorkbook.Sheets("Results2").range("A1")

Thì code trên phải sửa sao ạ?
Nếu đã có điều kiện cho mỗi file (đặc điểm nhận dạng cho từng loại file A và B) thì lọc luôn khi chọn - tức là chỉ hiển thị các file hợp lệ để chọn. Đồng thời, khi chọn xong thì kiểm tra luôn có phải đã chọn 1 file dạng A và 1 file dạng B không, nếu không phải thì yêu cầu chọn lại chứ đừng để cho chọn rồi rồi lại bảo chọn không đúng.
Bạn xem code và dữ liệu mẫu trong file đính kèm.
 

File đính kèm

  • Import data.rar
    87.4 KB · Đọc: 18
Upvote 0
@Nguyễn Hoàng Oanh Thơ
Lời khuyên vẫn nên vận dụng cái "hiện đại".
Nghe OT nói đang học VBA không biết học tới đâu rồi.
Hôm trước thấy trả lời bài viết rất tốt. Sao nay lại chững bước với vấn đề tương tự thế này

Code dưới gọn gàn hơn Code tôi gợi ý lúc trước
PHP:
Function GetFileFullname(FolderPath As String, Optional sDesc As String = "Excel", _
                                             Optional sFilter As String = "*.xls") As Variant
  GetFileFullname = Array()
  Dim Arr(), k, it
  With Application.FileDialog(msoFileDialogOpen)
    .ButtonName = "&Open" 'Nút chỉ thị
    .initialFilename = FolderPath 'Đi đến đường dẫn cho trước
    '.Filters.Delete(1) '
    .Filters.Clear 'Xóa gợi ý các loại tệp mở rộng
    .Filters.Add sDesc, sFilter 'Bắt đầu thêm lại Gợi ý - Mặc định
    .Filters.Add "All File", "*.*" 'Thêm 1 Gợi ý nữa
    .Title = "File Open" 'Tiêu đề
    .InitialView = msoFileDialogViewDetails 'Kiểu sắp xếp để xem
    .AllowMultiSelect = True 'Cho phép chọn nhiều tệp
    If .show = -1 Then
      For Each it In .SelectedItems
        ReDim Preserve Arr(k): Arr(k) = it
        k = k + 1
      Next it
      GetFileFullname = Arr
    End If
  End With
End Function

Xin chào @HeSanbi,
Đúng là vấn đề lấy dữ liệu từ nguồn chưa xác định rõ cụ thể đường dẫn và tên file OT đã nhiều va chạm đến , nhưng lần nào gặp phải trường hợp lựa chọn file trong số file đã chọn để lấy dữ liệu như trường hợp này.
Cảm ơn HeSanbi các code trong bài viết.
OT sẽ cố gắng tìm hiểu ạ.
----------------------
Nếu đã có điều kiện cho mỗi file (đặc điểm nhận dạng cho từng loại file A và B) thì lọc luôn khi chọn - tức là chỉ hiển thị các file hợp lệ để chọn. Đồng thời, khi chọn xong thì kiểm tra luôn có phải đã chọn 1 file dạng A và 1 file dạng B không, nếu không phải thì yêu cầu chọn lại chứ đừng để cho chọn rồi rồi lại bảo chọn không đúng.
Bạn xem code và dữ liệu mẫu trong file đính kèm.

Xin chào huuthang_bd,
Code của anh và file anh đính kèm đúng với mong muốn của OT rồi ạ. OT sẽ phát triển thêm theo ý mình.
OT cảm ơn anh Hữu Thắng nhiều ạ.
 
Upvote 0
Mã:
Private Sub Worksheet_Change(ByVal Target As Range)
     Dim a As Long, lr As Long, i As Long, j As Byte
     Dim arr, arr1
     If Target.Address = "$C$1" Then
       With Sheet1
         lr = .Range("B" & Rows.Count).End(xlUp).Row
         If lr < 3 Then MsgBox "khong co du lieu": Exit Sub
         arr = .Range("A3:E" & lr).Value
         ReDim arr1(1 To UBound(arr, 1), 1 To 5)
         For i = 1 To UBound(arr, 1)
             If arr(i, 1) = Target.Value Then
                a = a + 1
                For j = 1 To 5
                    arr1(a, j) = arr(i, j)
                Next j
             End If
         Next i
       End With
       With Sheet2
            lr = .Range("B" & Rows.Count).End(xlUp).Row
            If lr > 2 Then .Range("a3:e" & lr).ClearContents
            If a Then .Range("A3").Resize(a, 5).Value = arr1
       End With
     End If
End Sub

a/c GIÚP EM DỊCH CÁI CODE NÀY VỚI , MÌNH KHÔNG HIỂU CHỔ 2 HÀM FOR LỒNG VÀO NHAU !!!
 
Upvote 0
Mã:
         For i = 1 To UBound(arr, 1)
1             If arr(i, 1) = Target.Value Then
                a = a + 1
3               For j = 1 To 5
                    arr1(a, j) = arr(i, j)
  5              Next j
             End If
         Next i
a/c GIÚP EM DỊCH CÁI CODE NÀY VỚI , MÌNH KHÔNG HIỂU CHỔ 2 HÀM FOR LỒNG VÀO NHAU !!!
Vòng lặp ngoài (theo tham biến i) duyệt từ đầu đến cuối mảng (dữ liệu)
D1: (Nếu dòng đang duyệt) thỏa điều kiện thì thực hiện các lệnh trước D6
D2: Tăng biến đềm a lên 1 đơn vị
D3: Tạo vòng lặp theo cột (1 -> 5)
D4 Ghi 5 giá trị ứng với 5 cột của dòng dữ liệu (thỏa Đ/K) vô mảng đích (Arr1())

Vui nếu giúp bạn ít nhiều
 
Lần chỉnh sửa cuối:
Upvote 0
Nhờ các thầy cô xem giúp em file đính kèm ạ. File đính em em cũng đang dùng code sẵn rồi. Nhưng lại chưa đúng ý lắm.
Các thầy cô có thể giúp em viết code. Hoặc tư vấn em nên dùng hàm gì trong excel để đáp ứng được các yêu cầu trong đó ạ.
Em cám ơn
Formmau
 
Upvote 0
Nhờ các thầy cô xem giúp em file đính kèm ạ. File đính em em cũng đang dùng code sẵn rồi. Nhưng lại chưa đúng ý lắm.
Các thầy cô có thể giúp em viết code. Hoặc tư vấn em nên dùng hàm gì trong excel để đáp ứng được các yêu cầu trong đó ạ.
Em cám ơn
Formmau
Bấm vào Link của bạn nó ra cái này
1545918324237.png
Nếu không phải là gải thích, gỡ rối về Code Bạn lập Topic mới sẽ có nhiều người tư vấn cho Bạn
 
Upvote 0

File đính kèm

  • Formmau1.rar
    144.9 KB · Đọc: 4
Upvote 0
. . . . (1) File đính em cũng đang dùng code sẵn rồi. Nhưng lại chưa đúng ý lắm.
(2) Các thầy cô có thể giúp em viết code. Hoặc tư vấn em nên dùng hàm gì trong excel để đáp ứng được các yêu cầu trong đó ạ.
(1) Trong file không thấy miếng Code nào cả, nên chưa thể biết ý bạn là sao?
(2) Trong file có mỗi trang dữ liệu; Các dữ liệu thuộc 31 dòng & trãi dài từ cột A đến cột G, TRong đó công thức tại 2 cột E & G đang lỗi
Nên không rõ iêu cầu của bạn là gì.

Tạm biết!
 
Lần chỉnh sửa cuối:
Upvote 0
Xin chào các bạn.
Oanh Thơ tạo 1 hàm tìm kiếm địa chỉ của 1 chuỗi ký tự như sau:
Mã:
Function MyFind(txtFind As String, rng As Range) As Range
    If Not IsError(Application.Match(txtFind, rng, 0)) Then
         Set MyFind = Cells(Application.Match(txtFind, rng, 0), 1)
         Debug.Print MyFind.Address
    End If
End Function
Nhờ các bạn giúp đỡ làm thế nào để gán được địa chỉ của chuỗi cần tìm vào biến "txtAddress" khi chạy testMyFind:
Mã:
Sub testMyFind()
    Dim rngtxt As Range, txtAddress As Range
    Set rngtxt = ThisWorkbook.Worksheets("Sheet1").Range("A1:A" & 10000)
    MyFind "NguyenHoangOanhTho", rngtxt
End Sub
 
Upvote 0
Xin chào các bạn.
Oanh Thơ tạo 1 hàm tìm kiếm địa chỉ của 1 chuỗi ký tự như sau:
Mã:
Function MyFind(txtFind As String, rng As Range) As Range
    If Not IsError(Application.Match(txtFind, rng, 0)) Then
         Set MyFind = Cells(Application.Match(txtFind, rng, 0), 1)
         Debug.Print MyFind.Address
    End If
End Function
Nhờ các bạn giúp đỡ làm thế nào để gán được địa chỉ của chuỗi cần tìm vào biến "txtAddress" khi chạy testMyFind:
Mã:
Sub testMyFind()
    Dim rngtxt As Range, txtAddress As Range
    Set rngtxt = ThisWorkbook.Worksheets("Sheet1").Range("A1:A" & 10000)
    MyFind "NguyenHoangOanhTho", rngtxt
End Sub
Cái này thì gán bình thường thôi mà.
Mã:
Set  txtAddress = MyFind("NguyenHoangOanhTho", rngtxt)
 
Upvote 0
Xin chào các bạn.
Oanh Thơ tạo 1 hàm tìm kiếm địa chỉ của 1 chuỗi ký tự như sau:
Mã:
Function MyFind(txtFind As String, rng As Range) As Range
    If Not IsError(Application.Match(txtFind, rng, 0)) Then
         Set MyFind = Cells(Application.Match(txtFind, rng, 0), 1)
         Debug.Print MyFind.Address
    End If
End Function
Nhờ các bạn giúp đỡ làm thế nào để gán được địa chỉ của chuỗi cần tìm vào biến "txtAddress" khi chạy testMyFind:
Mã:
Sub testMyFind()
    Dim rngtxt As Range, txtAddress As Range
    Set rngtxt = ThisWorkbook.Worksheets("Sheet1").Range("A1:A" & 10000)
    MyFind "NguyenHoangOanhTho", rngtxt
End Sub
Kết quả hàm MyFind là cái gì vậy bạn? Tôi chưa hình dung được áp dụng vào việc gì.
 
Lần chỉnh sửa cuối:
Upvote 0
O. Thơ cần tạo 1 hàm tìm kiếm địa chỉ của 1 chuỗi ký tự
Hình như bạn này đang cần tìm kiếm trên cột [A:A] 1 chuỗi kí tự nhập vô từ bàn fím
Nếu tìm thấy thì liệt kê địa chỉ ô được tìm thấy?

Nếu vấy thì thực hiện trong 1 macro thôi, gồm các công đoạn sau:

Nhấp kí tự cần tìm vô 1 tham biến (kiểu chuỗi) bằng hàm InputBox()
Tới đây có thể có chí ít các trường hợp như sau:
1./ Không tìm thấy: Trả lời "Nothing"
2./ Tìm thấy chỉ có 1 ô: Trả vế địa chỉ ô đó
3./ Tìm thấy từ 2 ô trở lên:
Khai báo từ đầu 1 mảng ghi kết quả của công cuộc tìm kiếm đó
Trả về là dẫy địa chỉ các ô được tìm thấy.

Ngoài ra cũng nói trước là: Công cuộc tìm kiếm này có fải tìm nguyên thể hay chỉ tìm gần đúng,
Ví dụ tìm mọi người có họ là 'Nguyễn' hay họ & đệm là 'Nguyễn Văn',. . . . (?)
Tìm chữ hoa lẫn chữ thường, chuỗi thể hiện ngày-tháng
Trị cầm tìm là kiểu số, như 2019
Trị cần tìm là thể loại 'Ngày-Tháng-Năm',. . . .

Dù gì thì cũng không nhất thiết fải viết hàm
Vì fương thức FIND() sẽ chỉ tìm 1 lần duy nhất, ta không thu kết quả của FinNext() (Kết quả của FindNext chỉ thấy trên cửa số Immediate mà thôi.)
. . . . . .
Mong fản hồi từ bạn & chúc vui khi sắp sang xuân!
 
Upvote 0
Xin cảm ơn chú @giaiphap ,anh @huuthang_bd ,bác @SA_DQ nhiều ạ.

OT sử dụng hàm MyFind với mục đích tìm 1 chuỗi trong một vùng dữ liệu bao gồm các ô gộp(trộn) ạ, vì phương thức find không tìm kiếm được với các ô bị trộn(gộp).
Mới đầu OT cũng viết như chú @giaiphap rồi nhưng chắc do viết sai lỗi chính tả trong code nên báo lỗi đỏ, loay hoay mãi không được nên gửi lên GPE để hỏi ạ.
Cảm ơn bác @SA_DQ cháu đã xử lý được vấn đề với hàm MyFind rồi ạ.
Kính chúc Bác/Chú/Anh năm mới nhiều sức khỏe.
Oanh Thơ
 
Upvote 0
OT sử dụng hàm MyFind với mục đích tìm 1 chuỗi trong một vùng dữ liệu bao gồm các ô gộp(trộn) ạ, vì phương thức find không tìm kiếm được với các ô bị trộn(gộp).
Trong các hàm UDF thì mình sẽ thử, nhưng FIND() vẫn có thể tìm trong các ô trộn như thường (trong macro); Chỉ là fải xài với tí chút mẹo
Ví dụ tìm trong cột dữ liệu có các ô trộn theo:
Cột, có nghĩa là vài 3 ô trong cột bị trộn lại thì ta fải tăng vùng tìm kiếm lên theo hàng (dòng), ví dụ từ 99 hàng lên 120 hàng chẵng hạn
Hàng, có nghĩa là vài hàng nào đó trong cột đã bị trộn ô theo hàng thì vùng tìm kiếm cần tăng số cột lên thêm chục hay hơn số cột.

Còn trong UDF, mình xin nhắc lại là FINDNext chỉ cho ta kết quả trên cửa số Immediate mà thôi.
 
Upvote 0
Trong các hàm UDF thì mình sẽ thử, nhưng FIND() vẫn có thể tìm trong các ô trộn như thường (trong macro); Chỉ là fải xài với tí chút mẹo
Ví dụ tìm trong cột dữ liệu có các ô trộn theo:
Cột, có nghĩa là vài 3 ô trong cột bị trộn lại thì ta fải tăng vùng tìm kiếm lên theo hàng (dòng), ví dụ từ 99 hàng lên 120 hàng chẵng hạn
Hàng, có nghĩa là vài hàng nào đó trong cột đã bị trộn ô theo hàng thì vùng tìm kiếm cần tăng số cột lên thêm chục hay hơn số cột.

Còn trong UDF, mình xin nhắc lại là FINDNext chỉ cho ta kết quả trên cửa số Immediate mà thôi.

Cháu cảm ơn bác Sa,
Nghĩa là mở rộng vùng tìm kiếm so với vùng chứa dữ liệu thì vẫn sử dụng được phương thức Find ạ.
Thảo nào khi cháu thao tác thủ công crtl+F vẫn tìm được với các ô trộn nhưng khi chạy code trong vùng có dữ liệu thì không được, cháu sẽ thử lại ạ.
 
Upvote 0
Tôi cũng có lúc nghĩ nhầm. Cứ đổ tôi cho ghép ô nhưng không phải 100% là như vậy.

Giả sử ta tìm trong cột I, nhưng Ik:Nk, Im:Nm, Ip:Np, với k, m, q là các số nguyên dương nào đó, là các ô ghép (tức tìm trong cột nhưng các ô được ghép theo dòng chứ không phải theo cột đang tìm kiếm) thì
Mã:
Set rng = ThisWorkbook.Worksheets("DL").Range("I1:I" & Rows.Count).Find(Target.Value, , xlValues, xlWhole, xlByColumns, xlNext)
sẽ trả về rng = Nothing.

Nhưng
Mã:
Set rng = ThisWorkbook.Worksheets("DL").Range("I1:I" & Rows.Count - 1).Find(Target.Value, , xlValues, xlWhole, xlByColumns, xlNext)

sẽ trả về ô merge trong cột I mà có giá trị Target.Value

Tóm lại sự khác nhau chỉ là Rows.Count - 1 thay cho Rows.Count. Hoặc không dùng Rows.Count mà tìm dòng cuối có dữ liệu bằng End(xlUp)

Tóm lại không bắt buộc phải mở rộng (tìm dòng cuối có dữ liệu bằng End(xlUp) rồi FIND trong vùng đó thôi). Còn nếu lười không xác định vùng dữ liệu mà chỉ dùng mở rộng thì không được mở rộng tới Rows.Count. Chỉ mở rộng cùng lắm tới Rows.Count-1
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom