So sánh 3 cách lấy dữ liệu từ 1 file đang đóng (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Maika8008

Thành viên gạo cội
Tham gia
12/6/20
Bài viết
4,765
Được thích
5,742
Donate (Momo)
Donate
Giới tính
Nam
Với Excel chúng ta thường có nhu cầu lọc lựa, lấy dữ liệu từ 1 file đang trạng thái đóng đã biết trước đường dẫn và địa chỉ tham chiếu vùng dữ liệu, nhưng lại không muốn tự tay mở nó ra để chép 1 cách thủ công qua file đang làm. Với VBA, chúng ta có 3 cách để tự động hóa khâu lấy dữ liệu này.

Cách 1: Mở trực tiếp file lên, lấy dữ liệu xong đóng lại:
Rich (BB code):
Sub GetDataByOpenFile()
Dim Wb As Workbook, WbS As Workbook
Dim sFullName$, tmr#

tmr = Timer()
Application.ScreenUpdating = False
sFullName = "D:\GoogleDrive2\CaNhan\VBA\MapVN.xlsx"  'Duong dan file du lieu
Set Wb = ThisWorkbook
Set WbS = Workbooks.Open(sFullName)
WbS.Sheets("VNxy").Range("A1:D100").Copy Wb.Sheets("KQ").Range("A1")
WbS.Close False
Application.ScreenUpdating = True
Msgbox Timer() – tmr  'Thoi gian thuc hien
End Sub
- Ưu điểm của cách 1 là trực quan, ta có thể tạm ngừng lệnh, chạy từng bước để xem kết quả trung gian. Dữ liệu có thế nào chép sang thế ấy hoặc có thể tùy ý chép riêng định dạng, công thức, giá trị…

- Nhược điểm cách 1 là thời gian thực thi khá chậm, mất khoảng 1,4 giây cho việc mở file, chép dữ liệu, đóng file. (Thời gian ở đây là trong điều kiện thử nghiệm cụ thể của tác giả, chỉ để so sánh tốc độ thực hiện các cách với nhau. Thời gian đó sẽ khác đi khi dùng ở máy khác, dùng 1 file nguồn khác…)

Cách 2: Mở file bằng ADODB:
Rich (BB code):
Sub GetDataByADODB()
Dim Rec As Object, rs As Object
Dim sFullName$, iCol&, tmr#

tmr = Timer()
sFullName = "D:\GoogleDrive2\CaNhan\VBA\MapVN.xlsx"   'Duong dan file du lieu
Application.ScreenUpdating = False
Set Rec = CreateObject("ADODB.Connection")
With Rec
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .ConnectionString = "Data Source=" & sFullName & ";" & _
              "Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
        .Open
End With
        Set rs = Rec.Execute("Select * From [VNxy$A1:D100]")
        Sheets("KQ").Range("A2").CopyFromRecordset rs
        For iCol = 0 To rs.Fields.Count - 1   'Chep tieu de cọt
                Sheets("KQ").Cells(1, iCol + 1).Value = rs.Fields(iCol).Name
        Next
        Set rs = Nothing
        Msgbox Timer() – tmr  'Thoi gian thuc hien
        Application.ScreenUpdating = True
End Sub
- Ưu điểm của cách 2 là thực thi nhanh, chỉ mất cỡ 0,2 giây, và người dùng không nhận biết được file đóng mở.

- Nhược điểm cách 2 là:

+ Trong đa số trường hợp phải mất công khắc phục việc chạy lệnh đối với tiêu đề có dấu tiếng Việt (Có cách khác không bị ảnh hưởng bởi tiêu đề tiếng Việt. Nhưng vấn đề này sẽ được trình bày ở 1 bài khác, có sự so sánh việc sử dụng của 2 cách).

+ Những ai chưa rành cú pháp SQL và lồng các biến vào câu lệnh SQL có thể gặp trở ngại khi điều kiện truy vấn phức tạp.

+ Gặp dữ liệu có dấu phân cách thập phân với các máy đã được dịnh dạng trong Control Panel là dấu phẩy thì sẽ có rắc rối với kết quả chép ra. Thay vì đúng là 144,12 thì kết quả chép ra ở đây là 14412,00.

Để khắc phục nhược điểm này thì phải thêm mã lệnh để chuyển định dạng dấu phẩy thập phân trong Control Panel sang dấu chấm trước khi chạy truy vấn rồi chuyển lại dấu phẩy ngay sau truy vấn.

Khai báo và đặt hàm SetLocalSetting trên đầu Module:
Rich (BB code):
#If VBA7 Then

 Private Declare PtrSafe Function SetLocaleInfo _

 Lib "kernel32" Alias "SetLocaleInfoA" ( _

 ByVal Locale As LongPtr, _

 ByVal LCType As LongPtr, _

 ByVal lpLCData As String) As Boolean

 

 Private Declare PtrSafe Function GetUserDefaultLCID% Lib "kernel32" ()

#Else

 Private Declare Function SetLocaleInfo _

 Lib "kernel32" Alias "SetLocaleInfoA" ( _

 ByVal Locale As Long, _

 ByVal LCType As Long, _

 ByVal lpLCData As String) As Boolean

 

 Private Declare Function GetUserDefaultLCID% Lib "kernel32" ()

#End If

 

 Private Const LOCALE_SDECIMAL = &HE

 

 Private Function SetLocalSetting(LC_CONST As Long, Setting As String) As Boolean

 Call SetLocaleInfo(GetUserDefaultLCID(), LC_CONST, Setting)

 End Function
Với Sub GetDataByADODB() ở trên, thêm lệnh này trước lệnh truy vấn SQL:

Call SetLocalSetting(LOCALE_SDECIMAL, ".")

Và thêm lệnh này ngay sau khi chạy xong truy vấn SQL:

Call SetLocalSetting(LOCALE_SDECIMAL, ",")



Cách 3: Dùng Macro 4. Cách này tôi dùng code từ nguồn:

https://www.giaiphapexcel.com/diendan/threads/dùng-macro-4-để-lấy-dữ-liệu-từ-1-file-đang-đóng.39312/
Rich (BB code):
Sub GetDataByMacro4()
Dim tmr#
tmr = Timer()
  Dim sFile As String, sSheet As String, sAddr As String
  sFile = "D:\GoogleDrive2\CaNhan\VBA\MapVN.xlsx"
  sSheet = "VNxy"
  sAddr = "A1:D100"  
  Sheets("KQ").Range("A1:D100") = GetData(sFile, sSheet, sAddr)
'Kích thuoc phai bang sAddr
  Msgbox Timer() – tmr  'Thoi gian thuc hien
End Sub

Function GetData(sFile As String, sSheet As String, sAddr As String)
      Dim pLink As String, iR As Long, iC As Long, Arr
      If Len(Dir(sFile)) Then
            Arr = Range(sAddr)
            pLink = "'" & Replace(sFile, Dir(sFile), "[" & Dir(sFile) & "]") & sSheet & "'!"
            For iR = 1 To Range(sAddr).Rows.Count
                  For iC = 1 To Range(sAddr).Columns.Count
                        Arr(iR, iC) = ExecuteExcel4Macro(pLink & Range(sAddr). _
Cells(iR, iC).Address(, , 2))
                  Next iC
            Next iR
            GetData = Arr
      End If
End Function
Với cách này, dù dữ liệu nguồn sAddr = "A1:D100" nhưng khi muốn hiển thị kết quả ít hơn thì bạn giảm kích thước vùng kết quả chỗ Sheets("KQ").Range("A1:D100"). Nếu tăng kích thước vùng kết quả thì sẽ bị #N/A ở các ô thừa.

- Thực tình thì không thấy ưu điểm nào của cách này ngoài việc nó lấy đúng số liệu nguồn như cách 1. Còn nhược điểm là quá chậm, phải đến tận 5 giây (gấp hơn 3 lần cách 1) thì mới lấy được dữ liệu cùng cỡ với các cách trên. Dòng tiêu đề sẽ hiển thị là 0 với tiêu đề nào chừa trống.

P/S: Tôi đính kèm file dữ liệu mà tôi đã dùng để test tốc độ thực thi code để các bạn có cùng 1 mẫu thử.
Trong bài có chỗ nào sai, sót thì các bác "gội" rồi mới "cạo" nhẹ nhàng góp ý giúp.
 

File đính kèm

Cám ơn bạn đã chia sẻ.
Tôi không phải là người thông thạo lý thuyết.
Tuy nhiên tôi hiểu là cách 2 là "Truy vấn dữ liệu từ file đang đóng mà không cần mở file".
Cơ bản là vậy nhưng đi sâu vào thì nó có lệnh Open đó: mở nhưng không thấy mở --=0
 
Upvote 0
Bạn có thể kiểm tra giúp mình thêm code trong bài viết này không, dạng link file ấy. Mình nghĩ code này sẽ nhanh.
 
Upvote 0
để công bằng test code hãy lấy 1 Files Excel có dữ liệu từ 5M to 20M xong dùng Workbooks.Open và ADODB lấy dữ liệu thì nó mới chính xác

Còn dữ liệu vài ngàn dòng ko tính
 
Upvote 0
Bạn có thể kiểm tra giúp mình thêm code trong bài viết này không, dạng link file ấy. Mình nghĩ code này sẽ nhanh.
Đọc mấy bài đầu thấy lấy trực tiếp bằng công thức và dùng macro 4 giống như link tôi dẫn trong bài #1. Để hồi rảnh tôi xem lại thử sao tốc độ lại khá hơn
Bài đã được tự động gộp:

để công bằng test code hãy lấy 1 Files Excel có dữ liệu từ 5M to 20M xong dùng Workbooks.Open và ADODB lấy dữ liệu thì nó mới chính xác

Còn dữ liệu vài ngàn dòng ko tính
Để rảnh tôi test chừng vài chục ngàn dòng xem.

Quả là Workbooks.Open nhanh hơn ADODB (4s so với 7s). Còn cách macro 4 chạy lâu quá tôi không chờ được, hic.

File 60 ngàn dòng không có công thức gì
 
Lần chỉnh sửa cuối:
Upvote 0
có file Excel trên 10M + công thức mảng tôi mở lên thôi cũng mệt đấy
Còn cái vụ macro4 lấy lên nếu báo #value xử lý dễ lắm ... xem lại mấy năm trước tôi đã code úp GPE
 
Upvote 0
Tôi đề nghị thêm 2 cách để so sánh về hiệu quả lẫn tốc độ:
Cách số 4: lấy bằng Power query, tôi thấy hiệu quả về tốc độ cũng như lấy dữ liệu lớn
Cách số 5: Lấy bằng Pandas Python tôi thấy cũng nhanh, mỗi tội hơi khó nhìn
Python tôi không thạo lắm, nên tôi đề nghị xem cách nạp bằng cách 4 sau đó dùng M Code hoặc Dax trong Power Pivot thì trực quan hơn
 
Upvote 0
Tôi đề nghị thêm 2 cách để so sánh về hiệu quả lẫn tốc độ:
Cách số 4: lấy bằng Power query, tôi thấy hiệu quả về tốc độ cũng như lấy dữ liệu lớn
Cách số 5: Lấy bằng Pandas Python tôi thấy cũng nhanh, mỗi tội hơi khó nhìn
Python tôi không thạo lắm, nên tôi đề nghị xem cách nạp bằng cách 4 sau đó dùng M Code hoặc Dax trong Power Pivot thì trực quan hơn
Các bác rành về mấy cách đó test xem, chứ tôi chỉ biết mỗi VBA thôi
 
Upvote 0
tất cả nhưng cách trên Giờ tôi bỏ ... mà sử dụng FireDAC của Delphi ko có gì liên quan tới Ms cả .... ai rảnh làm Data đi xong tôi Up DLL lên cho mà thử

Nhớ làm cái Data khủng gần tràn Sheet ấy ... Files to trên 10M
 
Upvote 0
Ngày xưa mình hay dùng ADO để lấy dữ liệu và báo cáo nhưng ADO nó có hạn chế số lượng dòng và cột, với lỗi data (nó phụ thuộc vào 8 dòng đầu bảng dữ liệu để quyết định kiểu dữ liệu nên nếu dữ liệu không chuẩn dễ gây sai data hoặc không lấy được dữ liệu)nên mình không bao giờ dùng nữa. Cứ theo cách thuần mà làm: open/ mảng/ dic.... Vì mình ít khi làm với dữ liệu excel lớn cả, với lại cũng không quan trọng lắm về tốc độ, nhanh chậm chênh nhau vài phút cũng khong thành vấn đề, miễnkết quả đúng là được.
Theo mình chỉ nên dùng ADO khi kết nới với CSDL chuẩn như Access, MS SQL...vì những hệ quản trị dữ liệu này đã định nghĩa kiểu dữ liệu rồi.
 
Upvote 0
Ngày xưa mình hay dùng ADO để lấy dữ liệu và báo cáo nhưng ADO nó có hạn chế số lượng dòng và cột, với lỗi data (nó phụ thuộc vào 8 dòng đầu bảng dữ liệu để quyết định kiểu dữ liệu nên nếu dữ liệu không chuẩn dễ gây sai data hoặc không lấy được dữ liệu)nên mình không bao giờ dùng nữa. Cứ theo cách thuần mà làm: open/ mảng/ dic.... Vì mình ít khi làm với dữ liệu excel lớn cả, với lại cũng không quan trọng lắm về tốc độ, nhanh chậm chênh nhau vài phút cũng khong thành vấn đề, miễnkết quả đúng là được.
Theo mình chỉ nên dùng ADO khi kết nới với CSDL chuẩn như Access, MS SQL...vì những hệ quản trị dữ liệu này đã định nghĩa kiểu dữ liệu rồi.
đồng ý là thế .... nhưng thớt này họ nói So sánh mà
 
Upvote 0
Tôi đưa 2 cách connect mà tôi thường dùng, connect file csv 21 triệu dòng và 15 cột
1. Python pandas mất khoảng 44s
2. Power query khoảng 5 phút (nãy do bấm trễ một chút)
Cả 2 cách trên dữ liệu lưu ở Ram
Máy tôi AMD 3700x , Ram 16G, SSD Read 3500M, file để ở SSD
Data : https://drive.google.com/file/d/1MgTowNES3NT3D1g6H8MMPPsqP1qa_FW-/view
1630490284602.png

1630490256172.png
 
Upvote 0
Tôi đưa 2 cách connect mà tôi thường dùng, connect file csv 21 triệu dòng và 15 cột
1. Python pandas mất khoảng 44s
2. Power query khoảng 5 phút (nãy do bấm trễ một chút)
Cả 2 cách trên dữ liệu lưu ở Ram
Máy tôi AMD 3700x , Ram 16G, SSD Read 3500M, file để ở SSD
Data : https://drive.google.com/file/d/1MgTowNES3NT3D1g6H8MMPPsqP1qa_FW-/view
View attachment 265225

View attachment 265224
Anh cho em xin code python tham khảo, em nạp 1tr dòng thì mất khoảng 9s, anh nạp 21tr dòng 44s thì nhanh quá!
Với lại nếu em nạp đuổi excel xlsx thì nó chạy vô cùng chậm, nó chậm gấp 10 lần đuôi csv luôn, có cách nào cải thiện nạp đuôi xlsx tăng tốc độ không anh?
Cảm ơn anh!
 
Upvote 0
Nếu code trên Excel thì cứ như bài #11.
Còn thi tốc độ thì Python. :-p
 
Upvote 0
Anh cho em xin code python tham khảo, em nạp 1tr dòng thì mất khoảng 9s, anh nạp 21tr dòng 44s thì nhanh quá!
Với lại nếu em nạp đuổi excel xlsx thì nó chạy vô cùng chậm, nó chậm gấp 10 lần đuôi csv luôn, có cách nào cải thiện nạp đuôi xlsx tăng tốc độ không anh?
Cảm ơn anh!
Code nạp csv như hình đấy bạn, python nạp excel chậm lắm bạn nếu dữ liệu càng lớn vì file excel nó dạng dữ liệu nén, dữ liệu khoảng vài chục ngàn thì nạp excel được còn lớn hơn thì tốt nhất chuyển qua csv , đọc file thì nó cũng phụ thuộc vào cpu và tốc độ ssd bạn ạ nên máy bạn yếu nạp chậm hơn là bình thường bạn ạ
 
Upvote 0
Theo bài #1 thì chủ thớt muốn so sánh trong Excel không thôi nên tôi nghĩ chỉ dùng CSDL là excel chứ đừng dùng dạng khác (CSV).
Đây là cái data 1.1 triệu dòng, 26 cột Excel (103M) để các bạn test nhé. nhiều quá chạy mệt máy.
:)
Link: https://www.mediafire.com/file/62bdp3w1ml5cpsv/1.1Mil_Records.xlsx/file
 
Upvote 0
Mình chỉ đưa ra lời khuyên kiểu nếu thấy ADO nhanh mà lạm dụng dùng nó thì không nên thôi.
vậy vậy thì lập cái chủ đề mới nên thế này thế kia ... còn đây họ đang so sánh tốc độ thì ta cứ đưa ra so thôi... còn gì đó bàn 1 chuyên đề khác sẻ phù hợp hơn
Bài đã được tự động gộp:

Nếu code trên Excel thì cứ như bài #11.
Còn thi tốc độ thì Python. :p
đoán thôi ... hình như máy ko cài Python thì ko sử dụng được ... nếu có thì đó là *.EXE do python viết
Bài đã được tự động gộp:

Theo bài #1 thì chủ thớt muốn so sánh trong Excel không thôi nên tôi nghĩ chỉ dùng CSDL là excel chứ đừng dùng dạng khác (CSV).
Đây là cái data 1.1 triệu dòng, 26 cột Excel (103M) để các bạn test nhé. nhiều quá chạy mệt máy.
:)
Link: https://www.mediafire.com/file/62bdp3w1ml5cpsv/1.1Mil_Records.xlsx/file
Tôi tải về mở lên thôi cũng mệt .. thì Open + Macro4 chạy mất dép
 
Lần chỉnh sửa cuối:
Upvote 0
1630492665051.png
đó Open hoài ko lên luôn ...đổi lại tên File cũng ko lên
 
Upvote 0
Theo bài #1 thì chủ thớt muốn so sánh trong Excel không thôi nên tôi nghĩ chỉ dùng CSDL là excel chứ đừng dùng dạng khác (CSV).
Đây là cái data 1.1 triệu dòng, 26 cột Excel (103M) để các bạn test nhé. nhiều quá chạy mệt máy.
:)
Link: https://www.mediafire.com/file/62bdp3w1ml5cpsv/1.1Mil_Records.xlsx/file
Kết quả tốc độ Open là 62 giây còn ADODB là 485 giây (lâu quá) --=0

Tiện thể: database đó có 14 cột hà!
 
Upvote 0
Khoảng 30 giây bạn à. Nhanh thiệt! Như vậy có lẽ Provider Microsoft.ACE.OLEDB.12.0 thiết kế tối ưu cho Access?
Đương nhiên nha vì nó chuyên cho CSDL mà! Nhưng lưu ý, thử lần đầu nó kết nối nó sẽ nhiều thời gian hơn những lần sau.
 
Upvote 0
Code nạp csv như hình đấy bạn, python nạp excel chậm lắm bạn nếu dữ liệu càng lớn vì file excel nó dạng dữ liệu nén, dữ liệu khoảng vài chục ngàn thì nạp excel được còn lớn hơn thì tốt nhất chuyển qua csv , đọc file thì nó cũng phụ thuộc vào cpu và tốc độ ssd bạn ạ nên máy bạn yếu nạp chậm hơn là bình thường bạn ạ
Máy bác đúng là mạnh hơn máy em nhiều. Máy em có corei7 ram 8gb, data của em tận 40 cột. Nên khả năng em nạp python 1tr dòng × 40 cột thời gian mất 9s chắc cũng hợp lý. Có cách nào nạp đuôi xlsx tốc độ nhanh thì tốt, ko lại mất công convert sang csv hơi tốn công.
 
Upvote 0
... Với VBA, chúng ta có 3 cách để tự động hóa khâu lấy dữ liệu này.
Bạn muốn so sánh theo phương diện lý thuyết hay thực hành?
Lý thuyết: thực sự mỗi cách nó làm cái gì?
Thực hành: ở đây (GPE), khi nói thựck hành là người ta muốn nói tốc độ. Tôi không cùng quan niệm nên mạn phép không bàn tới.
 
Upvote 0
Bạn muốn so sánh theo phương diện lý thuyết hay thực hành?
Lý thuyết: thực sự mỗi cách nó làm cái gì?
Thực hành: ở đây (GPE), khi nói thựck hành là người ta muốn nói tốc độ. Tôi không cùng quan niệm nên mạn phép không bàn tới.
Tôi muốn các anh em có kiến thức cơ bản có cái nhìn tổng quan về các phương pháp. Còn với gạo cội thì tôi cần các bác góp ý, bổ sung để mà tôi còn học hỏi.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi muốn các anh em có kiến thức cơ bản có cái nhìn tổng quan về các phương pháp. Còn với gạo cội thì tôi cần các bác góp ý, bổ sung để mà tôi còn học hỏi.
Cây gạo là một trong những loại cây có thể sống lâu năm và lớn thành đại thụ. Vì vậy mới có thành ngữ gạo cội.
Tôi thích đọc sách cho nên biết nhiều lý thuyết thôi. Gọi đại thụ thì chưa xứng đáng.

Cách 1 dùng chính Excel để mở file, đọc lấy dữ liệu, và đóng lại khi dùng xong. Nó là cách trực tiếp và giản dị nhất.

Cách 3 là cách người ta dùng khi cần lấy dữ liệu ở chính xác một vài chỗ. Nó chính thức là sử dụng liên kết từ file Excel này đến file Excel khác. Tương tự như ở một cell nào đó bạn có công thức =[tên file]'tên sheet'!địa chỉ cell.
Nói cách khác, phương pháp này cũng dùng Excel để đọc file.
Chú: vì mã nguồn bạn đưa ra là người ta biểu diễn cách lấy một mảng dữ liệu, cho nên có ba cái mớ vòng lặp để đọc từng ô và nhét vào mảng.

Cách 2 là cách khá thú vị. ADO là tên viết tắt ActiveX Data Object. Cái tên nói lên rõ rằng nó là một đối tượng thuộc loại ActiveX (gồm COM và OLE). Và đối tượng này chuyên về đọc/xử lý dữ liệu.
Khi đọc file Excel, ADO không dùng Excel mà dùng cách riêng của nó (hỏi mấy cha viết code đối tượng mới biết nó thực sự mở file và đọc hạ tầng cơ sở dữ liệu bằng phương pháp nào). Sau khi kết nói thì ADO coi cái file Excel kia như một CSDL. Để có thể truy vấn và xử lý CSDL dạng Excel, Microsoft đã chọn Access làm cỗ máy dịch và thi hành lệnh SQL. Tất cả mọi lệnh SQL đều phải tuân theo tiêu chuẩn Access Query. Nếu thay file Excel bằng SQL Server thì phải chọn cỗ máy SQL. Và mọi lệnh SQL đều phải theo tiêu chuẩn T-SQL.
Người ta dùng ADO chủ yếu là vì tiện lợi của lệnh SQL, có thể tóm gom tổng kết dữ liệu luôn trước khi đưa ra kết quả. Điển hình là các dạng đối chiếu (join by keys), lọc (where), sắp xếp (sort), nhóm (group).
Về sau này, với Power BI thì ADO mất dần đi lợi thế của SQL. Data Model của Power BI dùng cỗ máy SQL Server (Express) cho nên hiệu quả hơn Access nhiều.
 
Upvote 0
Hãy thứ trên Data.sqlite xem ... thì nó xem Access bé tẹo :D
Bạn nạp dữ liệu đó vô sqlLite3 và test lấy dữ liệu vô Excel bằng thư viện của Delphi xem như thế nào.
Tôi dùng ADO với driver sql3ODBC thì cũng mất tầm 48s cho 1tr records, còn với database Access mất 18s

Screen Shot 2021-09-01 at 22.36.45.png
 
Upvote 0
Cây gạo là một trong những loại cây có thể sống lâu năm và lớn thành đại thụ. Vì vậy mới có thành ngữ gạo cội.
Tôi thích đọc sách cho nên biết nhiều lý thuyết thôi. Gọi đại thụ thì chưa xứng đáng.

Cách 1 dùng chính Excel để mở file, đọc lấy dữ liệu, và đóng lại khi dùng xong. Nó là cách trực tiếp và giản dị nhất.

Cách 3 là cách người ta dùng khi cần lấy dữ liệu ở chính xác một vài chỗ. Nó chính thức là sử dụng liên kết từ file Excel này đến file Excel khác. Tương tự như ở một cell nào đó bạn có công thức =[tên file]'tên sheet'!địa chỉ cell.
Nói cách khác, phương pháp này cũng dùng Excel để đọc file.
Chú: vì mã nguồn bạn đưa ra là người ta biểu diễn cách lấy một mảng dữ liệu, cho nên có ba cái mớ vòng lặp để đọc từng ô và nhét vào mảng.

Cách 2 là cách khá thú vị. ADO là tên viết tắt ActiveX Data Object. Cái tên nói lên rõ rằng nó là một đối tượng thuộc loại ActiveX (gồm COM và OLE). Và đối tượng này chuyên về đọc/xử lý dữ liệu.
Khi đọc file Excel, ADO không dùng Excel mà dùng cách riêng của nó (hỏi mấy cha viết code đối tượng mới biết nó thực sự mở file và đọc hạ tầng cơ sở dữ liệu bằng phương pháp nào). Sau khi kết nói thì ADO coi cái file Excel kia như một CSDL. Để có thể truy vấn và xử lý CSDL dạng Excel, Microsoft đã chọn Access làm cỗ máy dịch và thi hành lệnh SQL. Tất cả mọi lệnh SQL đều phải tuân theo tiêu chuẩn Access Query. Nếu thay file Excel bằng SQL Server thì phải chọn cỗ máy SQL. Và mọi lệnh SQL đều phải theo tiêu chuẩn T-SQL.
Người ta dùng ADO chủ yếu là vì tiện lợi của lệnh SQL, có thể tóm gom tổng kết dữ liệu luôn trước khi đưa ra kết quả. Điển hình là các dạng đối chiếu (join by keys), lọc (where), sắp xếp (sort), nhóm (group).
Về sau này, với Power BI thì ADO mất dần đi lợi thế của SQL. Data Model của Power BI dùng cỗ máy SQL Server (Express) cho nên hiệu quả hơn Access nhiều.
Thực ra tôi cũng định nói thêm về cái "thú vị" của cách 2 nhưng thấy sẽ làm mấy bạn làng nhàng như tôi mất hứng, bởi ngoài VBA lại phải cáng đáng thêm SQL. Thú thực với bác là dù lệnh SQL khá dễ hiểu, dễ dùng nhưng tôi chỉ dùng nó trong 1 số trường hợp đơn giản. Dùng Union cộng với biến ngày tháng là rối như canh hẹ.

Tôi thích dùng mảng vì nó phù hợp với cách suy nghĩ của tôi, gọi là tư duy cho nó sang. Cứ mở cái file lên ưa chép gì thì chép vào mảng rồi xào nấu nó, ưa món gì mà chẳng được. Cách đó chân phương, dễ hiểu, dễ làm.

Còn cách 3 là cách ngoài lề, tôi đưa vào cho rộng đường binh và đã nói VBA thì buộc phải có nó. Nếu tìm hiểu thêm thì chắc cũng có nhiều điều thú vị nhưng thôi, để dành thời gian cho 2 cách quan trọng hơn.

Tôi là người thực hành chứ không phải lý thuyết bởi xuất phát điểm là tôi viết VBA trước khi biết lý thuyết căn bản nữa kia. Do đó rất cảm ơn bác đã cho tôi thấy nhiều điều gọi là khẩu quyết để tìm tòi học hỏi trong lập trình.
 
Upvote 0
Tôi hay dùng ADO để import dữ liệu từ File đang đóng và cảm thấy giải pháp đó là vô địch.
Ngoài ra cũng tiện khi cần lấy kết quả cho mảng để làm việc khác (như nạp vào Combobox).
 
Upvote 0
Tôi hay dùng ADO để import dữ liệu từ File đang đóng và cảm thấy giải pháp đó là vô địch.
Ngoài ra cũng tiện khi cần lấy kết quả cho mảng để làm việc khác (như nạp vào Combobox).
À, bạn cho tôi hỏi làm thế nào để chuyển cái Recordset thành mảng? Tôi gán toàn bộ cho mảng nhưng không được?
 
Upvote 0
À, bạn cho tôi hỏi làm thế nào để chuyển cái Recordset thành mảng? Tôi gán toàn bộ cho mảng nhưng không được?
Ah,
Tôi cũng học từ sư phụ @NDU
Code bài #19, dùng hàm Getdata thôi
 
Upvote 0
Ah,
Tôi cũng học từ sư phụ @NDU
Code bài #19, dùng hàm Getdata thôi
Rồi, tôi đã biết thêm 1 chút: muốn lấy dữ liệu từ Recordset ra mảng thì phải dùng Rec.Getrows, nhưng cái Recordset đó có kích thước ngược lại với Datasource nên bước tiếp phải chép dòng thành cột ra mảng thì mới ra đúng như Datasource được. Thêm nữa (cũng lạ?) đã Sheet3.Range("A2").CopyFromRecordset Rec.Datasource thì sau đó không Getrows được nữa và ngược lại đã Getrows thì CopyFromRecordset không lỗi nhưng không ra kết quả gì cả.
 
Lần chỉnh sửa cuối:
Upvote 0
Rồi, tôi đã biết thêm 1 chút: muốn lấy dữ liệu từ Recordset ra mảng thì phải dùng Rec.Getrows, nhưng cái Recordset đó có kích thước ngược lại với Datasource nên bước tiếp phải chép dòng thành cột ra mảng thì mới ra đúng như Datasource được. Thêm nữa (cũng lạ?) đã Sheet3.Range("A2").CopyFromRecordset Rec.Datasource thì sau đó không Getrows được nữa và ngược lại đã Getrows thì CopyFromRecordset không lỗi nhưng không ra kết quả gì cả.
Tôi chưa hiểu ý của bạn lắm, nhưng tôi nạp kiểu này thì bình thường, như tôi đang dùng hàm GetData:
Mã:
Private Sub ComboBox1_Change()
  With ComboBox1
    .ListFillRange = ""
    .ColumnCount = 2
    .ColumnWidths = "50;100"
    .Width = "200"
    .ColumnHeads = True
    Dim lR As Long, arr
    FileName = "D:\EXCEL\GPEData3.xlsb"
    SheetName = "file 2"
    RangeAddress = "A4:B10"
    arr = GetData(FileName, SheetName, RangeAddress)
    .List() = arr
  End With
End Sub
 
Upvote 0
Tôi chưa hiểu ý của bạn lắm, nhưng tôi nạp kiểu này thì bình thường, như tôi đang dùng hàm GetData:
Mã:
Private Sub ComboBox1_Change()
  With ComboBox1
    .ListFillRange = ""
    .ColumnCount = 2
    .ColumnWidths = "50;100"
    .Width = "200"
    .ColumnHeads = True
    Dim lR As Long, arr
    FileName = "D:\EXCEL\GPEData3.xlsb"
    SheetName = "file 2"
    RangeAddress = "A4:B10"
    arr = GetData(FileName, SheetName, RangeAddress)
    .List() = arr
  End With
End Sub
Tôi đang nói về code trong GetData bạn à. Nó lấy ra mảng bằng cách:
1/ Lấy từ Recordset ra mảng tạm bằng .GetRows.
2/ Dùng 2 vòng lặp để biến cái mảng tạm đấy thành mảng có cấu trúc giống như data nguồn.

Còn đoạn: "Thêm nữa (cũng lạ?) đã Sheet3.Range("A2").CopyFromRecordset Rec.Datasource thì sau đó không Getrows được nữa và ngược lại đã Getrows thì CopyFromRecordset không lỗi nhưng không ra kết quả gì cả." là tôi thử nghiệm vào code ADO của tôi ở bài #1: Đã .GetRows thì không CopyFromRecordset được nữa và ngược lại
 
Upvote 0
Tôi đang nói về code trong GetData bạn à. Nó lấy ra mảng bằng cách:
1/ Lấy từ Recordset ra mảng tạm bằng .GetRows.
2/ Dùng 2 vòng lặp để biến cái mảng tạm đấy thành mảng có cấu trúc giống như data nguồn.
uhm, tôi cũng dân ngoại đạo, thực sự thì ngôn ngữ ADO tôi cũng không hiểu sâu, tôi cứ nạp bằng hàm Getdata là lấy data từ File khác (đang đóng) về.
Snag_149024d9.png
 
Upvote 0
Lại dở lý thuyết, dở hoài thành dở lái mất :p:
Vì với đa số ngôn ngữ lập trình, kể cả VBA, Array là loại mảng trọng cột (column major: xếp cột trước, dòng sau) cho nên hàm GetRows của ADO được viết để lấy dữ liệu theo cột. Tức là mỗi dòng mà GetRows đọc trên recordset sẽ được ghi lại vào một cột trong array.
Nếu mảng nhỏ, và dữ liệu không dài lắm thì có thể dùng hàm Transpose của worksheet để xoay mảng. Hình như giới hạn của Transpose là khoảng 400 dòng và mỗi string dưới 256 ký tự.

Nếu lấy dữ liệu trong Recordset nhiều lần thì nên tìm hiểu về cách đặt con trỏ.

Chú: ADO là một đối tượng. Recordset cũng là một đối tượng. GetRows là một phương thức của đối tượng Recordset. Mặt khác, CopyFromRecordSet là một phương thức của Range (Excel). Theo nguyên tắc lập trình hướng đối tượng thì đối tượng có thể biến hình tuỳ theo mọt vài bản chất nào đó. Muốn biết cách hoạt động của đối tượng ra sao thì phải tìm hiểu về thuộc tính và phương thức của chúng.

Chú 2 (thêm vào sau 12 phút): ở bài trước tôi quên nói thẳng rằng <quote>nhu cầu chọn lựa<endquote> theo nguyên tắc lập trình thì sẽ đặt trọng điểm trên điều kiện môi trường. Tuy quên giải thích, nhưng ở bài ấy tôi có đưa thẳng ra phương pháp chọn lựa theo ý cá nhân. Trái với đa số trên GPE, có lẽ gồm cả thớt, theo quan điểm tốc độ. Đó là một quan điểm chọn lựa "thực tế". Thực tế ở đây là sẽ đúng với hầu hết các trường hợp mà quý vị gặp. Chỉ có điều là quý vị cùng có suy nghĩ giống nhau cho nên các điều kiện môi trường và nhu cầu sẽ xếp giống nhau, các mẫu/loại dữ liệu mà quý vị test cũng giống nhau.
Khi gặp một môi trường khác, quý vị sẽ chưng hửng. Nhưng đó là chuyện của mai sau. Mai sau là lý thuyết, hiện tại mới là thực tế.
 
Lần chỉnh sửa cuối:
Upvote 0
Lại dở lý thuyết, dở hoài thành dở lái mất :p:
Vì với đa số ngôn ngữ lập trình, kể cả VBA, Array là loại mảng trọng cột (column major: xếp cột trước, dòng sau) cho nên hàm GetRows của ADO được viết để lấy dữ liệu theo cột. Tức là mỗi dòng mà GetRows đọc trên recordset sẽ được ghi lại vào một cột trong array.
Nếu mảng nhỏ, và dữ liệu không dài lắm thì có thể dùng hàm Transpose của worksheet để xoay mảng. Hình như giới hạn của Transpose là khoảng 400 dòng và mỗi string dưới 256 ký tự.

Nếu lấy dữ liệu trong Recordset nhiều lần thì nên tìm hiểu về cách đặt con trỏ.

Chú: ADO là một đối tượng. Recordset cũng là một đối tượng. GetRows là một phương thức của đối tượng Recordset. Mặt khác, CopyFromRecordSet là một phương thức của Range (Excel). Theo nguyên tắc lập trình hướng đối tượng thì đối tượng có thể biến hình tuỳ theo mọt vài bản chất nào đó. Muốn biết cách hoạt động của đối tượng ra sao thì phải tìm hiểu về thuộc tính và phương thức của chúng.

Chú 2: ở bài trước tôi quên nói thẳng rằng <quote>nhu cầu chọn lựa<endquote> theo nguyên tắc lập trình thì sẽ đặt trọng điểm trên điều kiện môi trường. Tuye uqeen giải thích, nhưng ở bài ấy tôi có đưa thẳng ra phương pháp chọn lựa theo ý cá nhân. Trái với đa số trên GPE, có lẽ gồm cả thớt, theo quan điểm tốc độ. Đó là một quan điểm chọn lựa "thực tế". Thực tế ở đây là sẽ đúng với hầu hết các trường hợp mà quý vị gặp. Chỉ có điều là quý vị cùng có suy nghĩ giống nhau cho nên các điều kiện môi trường và nhu cầu sẽ xếp giống nhau, các mẫu/loại dữ liệu mà quý vị test cũng giống nhau.
Khi gặp một môi trường khác, quý vị sẽ chưng hửng. Nhưng đó là chuyện của mai sau. Mai sau là lý thuyết, hiện tại mới là thực tế.
Hà hà. Tôi có rành lý thuyết đâu bác. Do đó tôi mới đặt vấn đề để có ai đó như bác gợi mở.
---------
"Nếu lấy dữ liệu trong Recordset nhiều lần thì nên tìm hiểu về cách đặt con trỏ.". Ồ! Hóa ra là vậy. Giữa GetRows và CopyFromRecordset tôi chen giữa bằng .MoveFirst thì ngon lành. Cám ơn bác!
 
Upvote 0
Code nạp csv như hình đấy bạn, python nạp excel chậm lắm bạn nếu dữ liệu càng lớn vì file excel nó dạng dữ liệu nén, dữ liệu khoảng vài chục ngàn thì nạp excel được còn lớn hơn thì tốt nhất chuyển qua csv , đọc file thì nó cũng phụ thuộc vào cpu và tốc độ ssd bạn ạ nên máy bạn yếu nạp chậm hơn là bình thường bạn ạ
Nếu python nạp excel chậm thì cũng giống power query a nhỉ
Việc import đơn giản chỉ là lấy dữ liệu về thì ADO nhanh và tiện lợi.
Tuy nhiên nếu cần thêm việc tổng hợp, tính toán, group theo vài tiêu chí thì phải dùng Power Query.
Em cũng chưa biết python là gì, ví dụ việc tổng hợp khoảng 30 file excel (mỗi file tầm 3M) thì python có lợi thế hơn Power Query không anh?
 
Upvote 0
Tùy theo nhu cầu mà ta có thể chọn cách nào đó cho phù hợp. Chủ thớt chỉ xét 1 phần nhỏ khi dùng ADO để so sánh.
 
Upvote 0
Cái hay của Range().CopyFromRecordSet là nó đảo chiều từ hàng thành cột của một mảng từ dữ liệu được xuất ra bằng ADO. Nhưng mình rất thích xử lý trên mảng "đảo ngược" được xuất ra bằng ADO. Các anh (chị) có biết tại sao không?
 
Upvote 0
Cái hay của Range().CopyFromRecordSet là nó đảo chiều từ hàng thành cột của một mảng từ dữ liệu được xuất ra bằng ADO. Nhưng mình rất thích xử lý trên mảng "đảo ngược" được xuất ra bằng ADO. Các anh (chị) có biết tại sao không?
Tôi chỉ biết là nhanh hơn, không qua khâu trung gian.
 
Upvote 0
Còn đoạn: "Thêm nữa (cũng lạ?) đã Sheet3.Range("A2").CopyFromRecordset Rec.Datasource thì sau đó không Getrows được nữa và ngược lại đã Getrows thì CopyFromRecordset không lỗi nhưng không ra kết quả gì cả." là tôi thử nghiệm vào code ADO của tôi ở bài #1: Đã .GetRows thì không CopyFromRecordset được nữa và ngược lại
Khi bạn muốn lấy lại thì bạn phải di chuyển con trỏ về dòng đầu tiên.
Ví dụ nếu bạn đã đổ recordset xuống sheet, nhưng vì lý do nào đó mà bạn muốn đổ nữa hoặc thực hiện điều gì đó thì xem ví dụ như sau:

Rich (BB code):
Sub test_ADO()
    With CreateObject("ADODB.Recordset")
        .Open "Select * from [Sheet1$]", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=Excel 12.0"
        Sheet2.Range("A2").CopyFromRecordset .DataSource
        .MoveFirst
        Sheet3.Range("A2").CopyFromRecordset .DataSource
    End With
End Sub
 
Upvote 0
Khi bạn muốn lấy lại thì bạn phải di chuyển con trỏ về dòng đầu tiên.
Ví dụ nếu bạn đã đổ recordset xuống sheet, nhưng vì lý do nào đó mà bạn muốn đổ nữa hoặc thực hiện điều gì đó thì xem ví dụ như sau:

Rich (BB code):
Sub test_ADO()
    With CreateObject("ADODB.Recordset")
        .Open "Select * from [Sheet1$]", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=Excel 12.0"
        Sheet2.Range("A2").CopyFromRecordset .DataSource
        .MoveFirst
        Sheet3.Range("A2").CopyFromRecordset .DataSource
    End With
End Sub
Tôi cũng vừa biết điều này và có nói ở bài #43.
 
Upvote 0
Upvote 0
Tôi không nói vấn đề đã được xử lý bằng CopyFromRecordSet, cái tôi muốn nói là cái mảng xuất ra từ GetRows đó bạn.
Tôi cũng muốn nói đến mảng đó đó nhưng tôi không biết bạn thích xử lý nó vì sao. Tôi chỉ biết là xử lý từ đó nhanh hơn thôi. Cứ coi hàng là cột thì xử lý bình thường như data nguồn thôi.
 
Upvote 0
Khi làm việc với Listbox và Combobox thì nó sẽ không cần chuyển mảng mà có thể đưa dữ liệu trực tiếp vào.
Đúng rồi em, đây cũng là một lợi thế và cái hay mà anh nói cũng liên quan đến 2 loại control này, nhưng đó là chuyện sau này, còn mình thích nó ở đây là ... gợi ý: mảng dạng này có số hàng là cố định (nó lấy field làm hàng) và số cột là biến động (nó lấy record làm cột mới ghê). Đây là mấu chốt để mình dùng thuật toán để Filter nhanh hơn mảng 2 chiều từ sheet.
 
Upvote 0
Đúng rồi em, đây cũng là một lợi thế và cái hay mà anh nói cũng liên quan đến 2 loại control này, nhưng đó là chuyện sau này, còn mình thích nó ở đây là ... gợi ý: mảng dạng này có số hàng là cố định (nó lấy field làm hàng) và số cột là biến động (nó lấy record làm cột mới ghê). Đây là mấu chốt để mình dùng thuật toán để Filter nhanh hơn mảng 2 chiều từ sheet.
Nói đến đây chợt nhớ ArrayList.
 
Upvote 0
Đúng rồi em, đây cũng là một lợi thế và cái hay mà anh nói cũng liên quan đến 2 loại control này, nhưng đó là chuyện sau này, còn mình thích nó ở đây là ... gợi ý: mảng dạng này có số hàng là cố định (nó lấy field làm hàng) và số cột là biến động (nó lấy record làm cột mới ghê). Đây là mấu chốt để mình dùng thuật toán để Filter nhanh hơn mảng 2 chiều từ sheet.
Cụ thể là anh sẽ thực hiện điều đó như thế nào?
 
Upvote 0
Với Excel chúng ta thường có nhu cầu lọc lựa, lấy dữ liệu từ 1 file đang trạng thái đóng đã biết trước đường dẫn và địa chỉ tham chiếu vùng dữ liệu, nhưng lại không muốn tự tay mở nó ra để chép 1 cách thủ công qua file đang làm. Với VBA, chúng ta có 3 cách để tự động hóa khâu lấy dữ liệu này.

Cách 1: Mở trực tiếp file lên, lấy dữ liệu xong đóng lại:
Rich (BB code):
Sub GetDataByOpenFile()
Dim Wb As Workbook, WbS As Workbook
Dim sFullName$, tmr#

tmr = Timer()
Application.ScreenUpdating = False
sFullName = "D:\GoogleDrive2\CaNhan\VBA\MapVN.xlsx"  'Duong dan file du lieu
Set Wb = ThisWorkbook
Set WbS = Workbooks.Open(sFullName)
WbS.Sheets("VNxy").Range("A1:D100").Copy Wb.Sheets("KQ").Range("A1")
WbS.Close False
Application.ScreenUpdating = True
Msgbox Timer() – tmr  'Thoi gian thuc hien
End Sub
- Ưu điểm của cách 1 là trực quan, ta có thể tạm ngừng lệnh, chạy từng bước để xem kết quả trung gian. Dữ liệu có thế nào chép sang thế ấy hoặc có thể tùy ý chép riêng định dạng, công thức, giá trị…

- Nhược điểm cách 1 là thời gian thực thi khá chậm, mất khoảng 1,4 giây cho việc mở file, chép dữ liệu, đóng file. (Thời gian ở đây là trong điều kiện thử nghiệm cụ thể của tác giả, chỉ để so sánh tốc độ thực hiện các cách với nhau. Thời gian đó sẽ khác đi khi dùng ở máy khác, dùng 1 file nguồn khác…)

Cách 2: Mở file bằng ADODB:
Rich (BB code):
Sub GetDataByADODB()
Dim Rec As Object, rs As Object
Dim sFullName$, iCol&, tmr#

tmr = Timer()
sFullName = "D:\GoogleDrive2\CaNhan\VBA\MapVN.xlsx"   'Duong dan file du lieu
Application.ScreenUpdating = False
Set Rec = CreateObject("ADODB.Connection")
With Rec
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .ConnectionString = "Data Source=" & sFullName & ";" & _
              "Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
        .Open
End With
        Set rs = Rec.Execute("Select * From [VNxy$A1:D100]")
        Sheets("KQ").Range("A2").CopyFromRecordset rs
        For iCol = 0 To rs.Fields.Count - 1   'Chep tieu de cọt
                Sheets("KQ").Cells(1, iCol + 1).Value = rs.Fields(iCol).Name
        Next
        Set rs = Nothing
        Msgbox Timer() – tmr  'Thoi gian thuc hien
        Application.ScreenUpdating = True
End Sub
- Ưu điểm của cách 2 là thực thi nhanh, chỉ mất cỡ 0,2 giây, và người dùng không nhận biết được file đóng mở.

- Nhược điểm cách 2 là:

+ Trong đa số trường hợp phải mất công khắc phục việc chạy lệnh đối với tiêu đề có dấu tiếng Việt (Có cách khác không bị ảnh hưởng bởi tiêu đề tiếng Việt. Nhưng vấn đề này sẽ được trình bày ở 1 bài khác, có sự so sánh việc sử dụng của 2 cách).

+ Những ai chưa rành cú pháp SQL và lồng các biến vào câu lệnh SQL có thể gặp trở ngại khi điều kiện truy vấn phức tạp.

+ Gặp dữ liệu có dấu phân cách thập phân với các máy đã được dịnh dạng trong Control Panel là dấu phẩy thì sẽ có rắc rối với kết quả chép ra. Thay vì đúng là 144,12 thì kết quả chép ra ở đây là 14412,00.

Để khắc phục nhược điểm này thì phải thêm mã lệnh để chuyển định dạng dấu phẩy thập phân trong Control Panel sang dấu chấm trước khi chạy truy vấn rồi chuyển lại dấu phẩy ngay sau truy vấn.

Khai báo và đặt hàm SetLocalSetting trên đầu Module:
Rich (BB code):
#If VBA7 Then

 Private Declare PtrSafe Function SetLocaleInfo _

 Lib "kernel32" Alias "SetLocaleInfoA" ( _

 ByVal Locale As LongPtr, _

 ByVal LCType As LongPtr, _

 ByVal lpLCData As String) As Boolean

 

 Private Declare PtrSafe Function GetUserDefaultLCID% Lib "kernel32" ()

#Else

 Private Declare Function SetLocaleInfo _

 Lib "kernel32" Alias "SetLocaleInfoA" ( _

 ByVal Locale As Long, _

 ByVal LCType As Long, _

 ByVal lpLCData As String) As Boolean

 

 Private Declare Function GetUserDefaultLCID% Lib "kernel32" ()

#End If

 

 Private Const LOCALE_SDECIMAL = &HE

 

 Private Function SetLocalSetting(LC_CONST As Long, Setting As String) As Boolean

 Call SetLocaleInfo(GetUserDefaultLCID(), LC_CONST, Setting)

 End Function
Với Sub GetDataByADODB() ở trên, thêm lệnh này trước lệnh truy vấn SQL:

Call SetLocalSetting(LOCALE_SDECIMAL, ".")

Và thêm lệnh này ngay sau khi chạy xong truy vấn SQL:

Call SetLocalSetting(LOCALE_SDECIMAL, ",")



Cách 3: Dùng Macro 4. Cách này tôi dùng code từ nguồn:

https://www.giaiphapexcel.com/diendan/threads/dùng-macro-4-để-lấy-dữ-liệu-từ-1-file-đang-đóng.39312/
Rich (BB code):
Sub GetDataByMacro4()
Dim tmr#
tmr = Timer()
  Dim sFile As String, sSheet As String, sAddr As String
  sFile = "D:\GoogleDrive2\CaNhan\VBA\MapVN.xlsx"
  sSheet = "VNxy"
  sAddr = "A1:D100" 
  Sheets("KQ").Range("A1:D100") = GetData(sFile, sSheet, sAddr)
'Kích thuoc phai bang sAddr
  Msgbox Timer() – tmr  'Thoi gian thuc hien
End Sub

Function GetData(sFile As String, sSheet As String, sAddr As String)
      Dim pLink As String, iR As Long, iC As Long, Arr
      If Len(Dir(sFile)) Then
            Arr = Range(sAddr)
            pLink = "'" & Replace(sFile, Dir(sFile), "[" & Dir(sFile) & "]") & sSheet & "'!"
            For iR = 1 To Range(sAddr).Rows.Count
                  For iC = 1 To Range(sAddr).Columns.Count
                        Arr(iR, iC) = ExecuteExcel4Macro(pLink & Range(sAddr). _
Cells(iR, iC).Address(, , 2))
                  Next iC
            Next iR
            GetData = Arr
      End If
End Function
Với cách này, dù dữ liệu nguồn sAddr = "A1:D100" nhưng khi muốn hiển thị kết quả ít hơn thì bạn giảm kích thước vùng kết quả chỗ Sheets("KQ").Range("A1:D100"). Nếu tăng kích thước vùng kết quả thì sẽ bị #N/A ở các ô thừa.

- Thực tình thì không thấy ưu điểm nào của cách này ngoài việc nó lấy đúng số liệu nguồn như cách 1. Còn nhược điểm là quá chậm, phải đến tận 5 giây (gấp hơn 3 lần cách 1) thì mới lấy được dữ liệu cùng cỡ với các cách trên. Dòng tiêu đề sẽ hiển thị là 0 với tiêu đề nào chừa trống.

P/S: Tôi đính kèm file dữ liệu mà tôi đã dùng để test tốc độ thực thi code để các bạn có cùng 1 mẫu thử.
Trong bài có chỗ nào sai, sót thì các bác "gội" rồi mới "cạo" nhẹ nhàng góp ý giúp.
Nếu dữ liệu vượt quá số dòng chứa ở sheet đích thì code cho cách 1 và 3 sẽ như thế nào vậy bạn?
 
Upvote 0
Nếu dữ liệu vượt quá số dòng chứa ở sheet đích thì code cho cách 1 và 3 sẽ như thế nào vậy bạn?
Thực chất mọi người nên ngầm hiểu dữ liệu nguồn tôi muốn lấy là Excel và chỉ chừng chục ngàn dòng chứ tôi không bao giờ biết "dữ liệu khủng" là thế nào. Tôi nghĩ lấy từ Excel qua Excel (đừng từ 2003 lấy 2007 trở lên) thì đâu có xảy ra tình huống đó.
 
Upvote 0
Cụ thể là anh sẽ thực hiện điều đó như thế nào?
Trong một danh sách có nhiều mục, bạn cần lọc người có tên Tuấn chẳng hạn, nhưng đồng thời phải lọc theo đó là ngày sinh, nơi ở, số điện thoại v.v... hoặc đơn giản chỉ lọc lấy 2 cột tên và mã số thôi:

1630562260713.png

Bình thường thì mình dùng 2 vòng lặp là một vòng duyệt danh sách và trong khi duyệt mình lại làm 1 mảng để lưu lại số hàng đã được chọn, sau đó từ mảng ghi số hàng đó mình duyệt 1 vòng lặp nữa để tạo một mảng kết quả.

Thì với dạng mảng từ GetRows này mình chỉ duyệt 1 vòng lặp đã có mảng kết quả ngay trong đó luôn rồi.
 
Upvote 0
Khi làm việc với Listbox và Combobox thì nó sẽ không cần chuyển mảng mà có thể đưa dữ liệu trực tiếp vào.
Trong một danh sách có nhiều mục, bạn cần lọc người có tên Tuấn chẳng hạn, nhưng đồng thời phải lọc theo đó là ngày sinh, nơi ở, số điện thoại v.v... hoặc đơn giản chỉ lọc lấy 2 cột tên và mã số thôi:

View attachment 265276

Bình thường thì mình dùng 2 vòng lặp là một vòng duyệt danh sách và trong khi duyệt mình lại làm 1 mảng để lưu lại số hàng đã được chọn, sau đó từ mảng ghi số hàng đó mình duyệt 1 vòng lặp nữa để tạo một mảng kết quả.

Thì với dạng mảng từ GetRows này mình chỉ duyệt 1 vòng lặp đã có mảng kết quả ngay trong đó luôn rồi.
Chào hai sếp, hai sếp làm ơn có thể cho em xin file kèm này tham khảo được không?
Các sếp nói chuyện với nhau em thấy hay quá nhưng em không hiểu gì hết.
 
Upvote 0
Nếu python nạp excel chậm thì cũng giống power query a nhỉ
Việc import đơn giản chỉ là lấy dữ liệu về thì ADO nhanh và tiện lợi.
Tuy nhiên nếu cần thêm việc tổng hợp, tính toán, group theo vài tiêu chí thì phải dùng Power Query.
Em cũng chưa biết python là gì, ví dụ việc tổng hợp khoảng 30 file excel (mỗi file tầm 3M) thì python có lợi thế hơn Power Query không anh?
Không bạn, nếu chỉ tính file excel thì việc nạp excel trong python còn chậm hơn power query nhiều, 30 file excel (mỗi file tầm 3M) thì Power query chắc hơn nửa tiếng quá, cùng dữ liệu đó nếu chuyển sang file csv chắc tầm 15 phút, còn dùng python khoảng 3 phút thôi với điều kiện là Ram đủ
Nếu connect excel tốc độ thì tôi nghĩ như nhau giữa ADO và Power query, Power query nó có thời gian chờ nên có thể chậm hơn chút không đáng kể, không tính phần transform thì tôi nghĩ Power query tiện hơn nhiều vì nó là tool mà
 
Lần chỉnh sửa cuối:
Upvote 0
Cái chủ đề này là so sánh thì tôi cũng nói liên quan tới nó 1 chút

1/ như ban đầu tôi nói lấy vài ngàn dòng xong dùng Open + Mcro4 lấy lên nó bay cái vèo .... nhưng khi dữ liệu lên 100M thì xếp 2 cái đó vào xó

2/ khi dùng ADODB lấy thì keo nó nhanh hơn SQLite mà xài Driver SQLite xong thông qua ADOB kết nối thì nó cũng như mục số 1 không công bằng tý nào cả

nếu muốn công bằng thì xài thuần ADODB của Ms và thuần SQLite mà lấy thì sẻ thấy được

3/ trên thế giới tôi thấy đa số họ nhắc tới ADOB và SQLite nhiều chứ ít ai nhắc tới Python để xử lý CSDL khủng

4/ linh sau là quốc tế họ test thuần trên từng Tools khác nhau ... họ chỉ nhắc tới mấy Tools mà tôi khoanh đó ... FireDAC là thuần SQLite + vvv


1630566143385.png


Còn bàn ra bàn vào thì tôi không có khả năng bàn nó ... chỉ thấy tầm quốc tế bàn về nó thế thôi
 
Upvote 0
Không bạn, nếu chỉ tính file excel thì việc nạp excel trong python còn chậm hơn power query nhiều, 30 file excel (mỗi file tầm 3M) thì Power query chắc hơn nửa tiếng quá, cùng dữ liệu đó nếu chuyển sang file csv chắc tầm 15 phút, còn dùng python khoảng 3 phút thôi với điều kiện là Ram đủ
Nếu connect excel tốc độ thì tôi nghĩ như nhau giữa ADO và Power query, Power query nó có thời gian chờ nên có thể chậm hơn chút không đáng kể, không tính phần transform thì tôi nghĩ Power query tiện hơn nhiều vì nó là tool mà
Không đến 30p đâu anh
Một file trung bình tầm 50,000 bản ghi, 15 trường.
File tổng hợp lấy 30 files, groupby lại lấy kết quả 5 trường, em chạy mất khoảng 8p.
 
Upvote 0
Không đến 30p đâu anh
Một file trung bình tầm 50,000 bản ghi, 15 trường.
File tổng hợp lấy 30 files, groupby lại lấy kết quả 5 trường, em chạy mất khoảng 8p.
Bạn để mỗi file tầm 3M tức là 3 triệu dòng mỗi file, tức là 30 file 90 triệu dòng phải không? nếu 90 triệu dòng mà file excel thì không có 8p đâu bạn, nếu chỉ có 50.000 dòng mỗi file thì trung bình mỗi s nó sẽ đọc được khoảng 20.000 dòng tức là 3s một file =>30 file tầm 2 phút thôi
 
Upvote 0
Thực chất mọi người nên ngầm hiểu dữ liệu nguồn tôi muốn lấy là Excel và chỉ chừng chục ngàn dòng chứ tôi không bao giờ biết "dữ liệu khủng" là thế nào. Tôi nghĩ lấy từ Excel qua Excel (đừng từ 2003 lấy 2007 trở lên) thì đâu có xảy ra tình huống đó.
Ví dụ bạn dùng file Excel nguồn có 1,048,576 dòng và bạn dùng 3 cách lần lượt ở bài 1 và lấy dữ liệu đưa vào 1 file nào đó bắt đầu từ địa chỉ A3 xem sao nhé.
 
Upvote 0
thì cứ bỏ bớt đi 76 dòng và 2 cột đi cho lành xong thử là biết thôi ... ko lại keo nó tràn Sheet :D
 
Upvote 0
Ví dụ bạn dùng file Excel nguồn có 1,048,576 dòng và bạn dùng 3 cách lần lượt ở bài 1 và lấy dữ liệu đưa vào 1 file nào đó bắt đầu từ địa chỉ A3 xem sao nhé.
Trời, cứ làm khó tôi chi vậy. 1 triệu dòng thì tôi đã thử và đã biết nó chạy rất lâu rồi.
 
Upvote 0
Trong một danh sách có nhiều mục, bạn cần lọc người có tên Tuấn chẳng hạn, nhưng đồng thời phải lọc theo đó là ngày sinh, nơi ở, số điện thoại v.v... hoặc đơn giản chỉ lọc lấy 2 cột tên và mã số thôi:

View attachment 265276

Bình thường thì mình dùng 2 vòng lặp là một vòng duyệt danh sách và trong khi duyệt mình lại làm 1 mảng để lưu lại số hàng đã được chọn, sau đó từ mảng ghi số hàng đó mình duyệt 1 vòng lặp nữa để tạo một mảng kết quả.

Thì với dạng mảng từ GetRows này mình chỉ duyệt 1 vòng lặp đã có mảng kết quả ngay trong đó luôn rồi.
Không cần bước sau anh, ta lọc trước rồi đẩy nó vào luôn. Không dùng vòng lặp.
 
Upvote 0
2/ khi dùng ADODB lấy thì keo nó nhanh hơn SQLite mà xài Driver SQLite xong thông qua ADOB kết nối thì nó cũng như mục số 1 không công bằng tý nào cả

nếu muốn công bằng thì xài thuần ADODB của Ms và thuần SQLite mà lấy thì sẻ thấy được

3/ trên thế giới tôi thấy đa số họ nhắc tới ADOB và SQLite nhiều chứ ít ai nhắc tới Python để xử lý CSDL khủng

4/ linh sau là quốc tế họ test thuần trên từng Tools khác nhau ... họ chỉ nhắc tới mấy Tools mà tôi khoanh đó ... FireDAC là thuần SQLite + vvv


View attachment 265279


Còn bàn ra bàn vào thì tôi không có khả năng bàn nó ... chỉ thấy tầm quốc tế bàn về nó thế thôi

Phải làm rõ mục số 2 bạn muốn nói cái gì, chứ đọc vậy không hiểu rồi.
- ADODB và sqlLite là 2 cái đối tượng khác nhau hoàn toàn. Một bên là thư viện với các phương thức, thuộc tính để kết nối tới CSDL bên ngoài, còn sqlLite là một ứng dụng xây dựng, chứa CSDL nên bạn nói "khi dùng ADODB lấy thì kêu nó nhanh hơn sqlLite.." là không hiểu rồi đó!
Bài test tôi có đề cập ở trên là "dùng ADODB kết nối tới CSDL sqlLite và CSDL Access" để xem ADODB lấy dữ liệu từ hệ quản trị CSDL nào nhanh? chứ ADODB và sqlLite có cùng loại đâu mà so sánh!!!
Một khi muốn kết nối tới CSDL nào đó thì phải dùng Driver nào cho phù hợp thì đối với sqlLite tôi chỉ biết nó cung cấp ODBC Driver thông qua file "sqlliteodbc.dll". Đối với Ms Access thì mặc định đã có sẳn Driver đi kèm khi cài Office rồi khỏi mất công kiếm Driver cho nó.
- "Xài thuần ADODB và thuần SQLLite" là sao bạn? thuần sqlLite tức là dùng ứng dụng sqlLiteStudio xuất (export) table sqlLite sang Excel? Tool export của sqlLiteStudio chỉ xuất được ra CSV, HTML, JSON..., không có Excel. Vậy từ Excel làm sao kết nối tới CSDL sqlLite? Bạn đừng nói dùng cái tool của Delphi nhé vì nó đã là của ngôn ngữ lập trình Delphi rồi, không còn là VBA Excel.
- Mục 3 là bạn phải cập nhật lại thông tin đi. Khi nói về Big Data (tạm gọi dữ liệu khủng đi như dữ liệu thương mại điện tử, ngân hàng, y tế, bán lẻ v.v..), Data science thì từ Python nó nằm trên đầu đó, bên cạnh đó còn có ngôn ngữ R, phải biết SQL (không phải sqlLite nhé) để truy vấn dữ liệu, Java, C++... và còn nhiều kỹ năng mềm khác nữa. Chắc chắc ADODB, và sqlLite không có nằm trong môn khoa học dữ liệu này đâu.
- Mục 4: mấy cái tool họ so sánh là của Delphi và chạy trên ngôn ngữ lập trình Delphi. Từ Delphi dùng các thư viện trên để truy vấn khau thác dữ liệu thì cái FireDAC là tốt hơn các thư viện còn lại. dùng thư viện FireDAC có thể kết nối hầu hết các ứng dụng quản trị CSDL hiện tại như: MS Access, SQLite, MySQL, SQL Server, Oracle, PostgreSQL... Bạn dùng từ "FireDAC là thuần sqlLite" thì khó hiểu thật.
 
Upvote 0
3/ trên thế giới tôi thấy đa số họ nhắc tới ADOB và SQLite nhiều chứ ít ai nhắc tới Python để xử lý CSDL khủng
Bạn đang nói select query hay xử lý dữ liệu, nếu nói xử lý dữ liệu thì tôi biết Python top 1 nhiều năm rồi ngoài thư viện Pandas nó còn thư viện Pyspark xử lý vài trăm GB dữ liệu
 
Upvote 0
Phải làm rõ mục số 2 bạn muốn nói cái gì, chứ đọc vậy không hiểu rồi.
- ADODB và sqlLite là 2 cái đối tượng khác nhau hoàn toàn. Một bên là thư viện với các phương thức, thuộc tính để kết nối tới CSDL bên ngoài, còn sqlLite là một ứng dụng xây dựng, chứa CSDL nên bạn nói "khi dùng ADODB lấy thì kêu nó nhanh hơn sqlLite.." là không hiểu rồi đó!
Bài test tôi có đề cập ở trên là "dùng ADODB kết nối tới CSDL sqlLite và CSDL Access" để xem ADODB lấy dữ liệu từ hệ quản trị CSDL nào nhanh? chứ ADODB và sqlLite có cùng loại đâu mà so sánh!!!
Một khi muốn kết nối tới CSDL nào đó thì phải dùng Driver nào cho phù hợp thì đối với sqlLite tôi chỉ biết nó cung cấp ODBC Driver thông qua file "sqlliteodbc.dll". Đối với Ms Access thì mặc định đã có sẳn Driver đi kèm khi cài Office rồi khỏi mất công kiếm Driver cho nó.
- "Xài thuần ADODB và thuần SQLLite" là sao bạn? thuần sqlLite tức là dùng ứng dụng sqlLiteStudio xuất (export) table sqlLite sang Excel? Tool export của sqlLiteStudio chỉ xuất được ra CSV, HTML, JSON..., không có Excel. Vậy từ Excel làm sao kết nối tới CSDL sqlLite? Bạn đừng nói dùng cái tool của Delphi nhé vì nó đã là của ngôn ngữ lập trình Delphi rồi, không còn là VBA Excel.
- Mục 3 là bạn phải cập nhật lại thông tin đi. Khi nói về Big Data (tạm gọi dữ liệu khủng đi như dữ liệu thương mại điện tử, ngân hàng, y tế, bán lẻ v.v..), Data science thì từ Python nó nằm trên đầu đó, bên cạnh đó còn có ngôn ngữ R, phải biết SQL (không phải sqlLite nhé) để truy vấn dữ liệu, Java, C++... và còn nhiều kỹ năng mềm khác nữa. Chắc chắc ADODB, và sqlLite không có nằm trong môn khoa học dữ liệu này đâu.
- Mục 4: mấy cái tool họ so sánh là của Delphi và chạy trên ngôn ngữ lập trình Delphi. Từ Delphi dùng các thư viện trên để truy vấn khau thác dữ liệu thì cái FireDAC là tốt hơn các thư viện còn lại. dùng thư viện FireDAC có thể kết nối hầu hết các ứng dụng quản trị CSDL hiện tại như: MS Access, SQLite, MySQL, SQL Server, Oracle, PostgreSQL... Bạn dùng từ "FireDAC là thuần sqlLite" thì khó hiểu thật.
à mà thôi ... nói ra nó dài dòng lắm ... Mạnh làm biếng lắm .. mà dân tự học nhiều khi câu từ + giải thích nó cứ lộn ngược lên ... thôi ko nhắc lại bài đó nữa he
 
Upvote 0
Bạn để mỗi file tầm 3M tức là 3 triệu dòng mỗi file, tức là 30 file 90 triệu dòng phải không? nếu 90 triệu dòng mà file excel thì không có 8p đâu bạn, nếu chỉ có 50.000 dòng mỗi file thì trung bình mỗi s nó sẽ đọc được khoảng 20.000 dòng tức là 3s một file =>30 file tầm 2 phút thôi
Có cách nào để đo thời gian mà background query chạy không anh?
 
Upvote 0
Upvote 0
VD danh sách có tên VŨ, VỤ, VÙ, VÚ gì đó, nhưng mình chỉ cần gõ chữ VU thì nó sẽ ra những chữ kia thì ADO khó có thể đáp ứng được.
Cái vụ tìm kiếm dạng này thì tôi vẫn dùng câu lệnh SQL được nhưng phải lồng thêm một cái hàm để xử lý chuỗi tìm kiếm.
Vd:
Mã:
Select * From tblNhanVien Where MaNV Like 'V[UÚŨÙỤ]'
 
Upvote 0
Cái vụ tìm kiếm dạng này thì tôi vẫn dùng câu lệnh SQL được nhưng phải lồng thêm một cái hàm để xử lý chuỗi tìm kiếm.
Vd:
Mã:
Select * From tblNhanVien Where MaNV Like 'V[UÚŨÙỤ]'
Nếu chỉ một vài chữ cố định thì không thành vấn đề, nhưng chữ viết tiếng Việt không biết bao nhiêu chữ thì làm sao mình xử lý kiểu này được.
 
Upvote 0
Nếu chỉ một vài chữ cố định thì không thành vấn đề, nhưng chữ viết tiếng Việt không biết bao nhiêu chữ thì làm sao mình xử lý kiểu này được.
Nói chung là chỉ xử lý 1 từ, nếu nhiều từ thì phải viết thêm :). Thực ra thì tìm vẫn ra nhưng tôi không cho tìm nhiều từ để chạy cho nhanh
VD: chuong, luan, lien

Screen Shot 2021-09-02 at 21.46.02.png
 
Lần chỉnh sửa cuối:
Upvote 0
Nói chung là chỉ xử lý 1 từ, nếu nhiều từ thì phải viết thêm :)
VD: chuong, luan, lien

View attachment 265304
Cái này chắc làm hẳn một bộ từ điển cho nó quá! Hay là làm cái hàm loại dấu tiếng Việt ngay trong CSDL để xử lý việc này? Mà ứng dụng thế nào thì mình cũng không rành cho lắm khi áp dụng vào ADO.
 
Upvote 0
Cái này chắc làm hẳn một bộ từ điển cho nó quá! Hay là làm cái hàm loại dấu tiếng Việt ngay trong CSDL để xử lý việc này? Mà ứng dụng thế nào thì mình cũng không rành cho lắm khi áp dụng vào ADO.
Nhìn vậy chứ nó cũng đơn giản. Chi viết cái hàm xử lý, dùng bảng tra các nguyên âm thôi (a,â, e, ê...y) và các biến thể với dấu thanh của nó + xử lý chuỗi. Bạn ngâm cứu chút chắc là ra thôi.
a = "a" & ChrW(224) & ChrW(225) & ChrW(227) & ChrW(7841) & ChrW(7843) a1 = ChrW(226) & ChrW(7845) & ChrW(7847) & ChrW(7849) & ChrW(7851) & ChrW(7853) ...

Cơ bản tôi hay dùng Recordset nên thường sử dụng câu lệnh SQL để xử lý mà ADO là dùng câu lệnh SQL nên áp dụng được thôi.
 
Upvote 0
Nhìn vậy chứ nó cũng đơn giản. Chi viết cái hàm xử lý, dùng bảng tra các nguyên âm thôi (a,â, e, ê...y) và các biến thể với dấu thanh của nó + xử lý chuỗi. Bạn ngâm cứu chút chắc là ra thôi.
a = "a" & ChrW(224) & ChrW(225) & ChrW(227) & ChrW(7841) & ChrW(7843) a1 = ChrW(226) & ChrW(7845) & ChrW(7847) & ChrW(7849) & ChrW(7851) & ChrW(7853) ...

Cơ bản tôi hay dùng Recordset nên thường sử dụng câu lệnh SQL để xử lý mà ADO là dùng câu lệnh SQL nên áp dụng được thôi.
Vậy thì khá rắc rối, thôi thì cứ bê nguyên cái dữ liệu theo điều kiện mình đặt ra, sau đó nếu cần gõ chữ nào thì lọc chữ đó cho nó lành. Phàm cái gì khó quá thì bỏ qua cho khỏe.

P/s: Mà cứ gõ ký tự lại kết nối với CSDL phải chăng là nó quá lâu hơn so với lọc qua mảng không?
 
Upvote 0
Trong một danh sách có nhiều mục, bạn cần lọc người có tên Tuấn chẳng hạn, nhưng đồng thời phải lọc theo đó là ngày sinh, nơi ở, số điện thoại v.v... hoặc đơn giản chỉ lọc lấy 2 cột tên và mã số thôi:

View attachment 265276

Bình thường thì mình dùng 2 vòng lặp là một vòng duyệt danh sách và trong khi duyệt mình lại làm 1 mảng để lưu lại số hàng đã được chọn, sau đó từ mảng ghi số hàng đó mình duyệt 1 vòng lặp nữa để tạo một mảng kết quả.

Thì với dạng mảng từ GetRows này mình chỉ duyệt 1 vòng lặp đã có mảng kết quả ngay trong đó luôn rồi.
Cách này hay đấy, sẽ bỏ được một vòng lặp, tốc độ vì thế sẽ cải thiện, dùng code sẽ phê hơn bình thường.
 
Upvote 0
Cách này hay đấy, sẽ bỏ được một vòng lặp, tốc độ vì thế sẽ cải thiện, dùng code sẽ phê hơn bình thường.
Nói về lọc dữ liệu trên ComboBox bằng array để tìm mục nào đó thì mình mới phát minh ra một kiểu lọc mà từ trước tới nay chưa một ai có thuật toán như mình, nó đảm bảo nhanh từ bằng đến gấp đôi gấp ba và nhiều hơn thế nữa nếu cứ tăng 1 ký tự! Nhưng mình đang hoàn thiện sẽ có dịp mình tặng cho mọi người cùng thưởng thức!
 
Upvote 0
Nói về lọc dữ liệu trên ComboBox bằng array để tìm mục nào đó thì mình mới phát minh ra một kiểu lọc mà từ trước tới nay chưa một ai có thuật toán như mình, nó đảm bảo nhanh từ bằng đến gấp đôi gấp ba và nhiều hơn thế nữa nếu cứ tăng 1 ký tự! Nhưng mình đang hoàn thiện sẽ có dịp mình tặng cho mọi người cùng thưởng thức!
Chia luôn để mọi người sẻ xem thế nào anh Nghĩa đẹp trai ơi.
 
Upvote 0
So sánh vẫn luôn là so sánh thôi và rất dễ bị tráo khái niệm
Nếu đã so sánh thì phải đồng (cùng ) nhiều thứ:
- Cùng File Dữ liệu
- Cùng File kết quả
- Cùng môi trường kết quả cuối cùng (file kết quả là đang mở hay là không mở ở Excel)
vv

Còn nếu chuyển qua môi trường khác như CSV, TextFile -- thì phải coi đó là bước trung gian, cần kể cả thời gian chuyển tự động qua bước trung gian đó.

Tóm lại, ai quen môi trường nào thì làm ở môi trường đó, và quy mô File cấu trúc File dữ liệu gốc , cũng như kết quả sẽ quyết định nên chọn cái nào: Chân phương, hay là tắt, lắt léo, hay sử dụng công cụ (Tool) khác ...
 
Upvote 0
Vậy thì khá rắc rối, thôi thì cứ bê nguyên cái dữ liệu theo điều kiện mình đặt ra, sau đó nếu cần gõ chữ nào thì lọc chữ đó cho nó lành. Phàm cái gì khó quá thì bỏ qua cho khỏe.

P/s: Mà cứ gõ ký tự lại kết nối với CSDL phải chăng là nó quá lâu hơn so với lọc qua mảng không?
Cách này tôi làm không phải dạng "tìm kiếm ngay khi gõ" (OnChange) mà tìm sau khi gõ xong (AfterUpdate).
Bên cạnh đó thì ADO Recordset cũng đã tải và nằm trong bộ nhớ rồi, chỉ cần Filter nó ra hoăc xoá Filter để trả lại Recordset nguyên vẹn, không cần kết nối, tải lại Recordset.
Cái vụ ADO recordset Filter có trong loạt bài của bạn HLMT.
 
Upvote 0
Cách này tôi làm không phải dạng "tìm kiếm ngay khi gõ" (OnChange) mà tìm sau khi gõ xong (AfterUpdate).
Bên cạnh đó thì ADO Recordset cũng đã tải và nằm trong bộ nhớ rồi, chỉ cần Filter nó ra hoăc xoá Filter để trả lại Recordset nguyên vẹn, không cần kết nối, tải lại Recordset.
Cái vụ ADO recordset Filter có trong loạt bài của bạn HLMT.
Tìm kiếm sau khi gõ thì gõ mệt nghỉ, còn mình chỉ gõ vài key là nó show ra cho mình chọn, đỡ mất công gõ, giống search trên Google đó thôi.
 
Upvote 0
Nói về lọc dữ liệu trên ComboBox bằng array để tìm mục nào đó thì mình mới phát minh ra một kiểu lọc mà từ trước tới nay chưa một ai có thuật toán như mình, nó đảm bảo nhanh từ bằng đến gấp đôi gấp ba và nhiều hơn thế nữa nếu cứ tăng 1 ký tự! Nhưng mình đang hoàn thiện sẽ có dịp mình tặng cho mọi người cùng thưởng thức!
Trước giờ mình chỉ biết cách lọc trên mảng, không nghĩ là có những cách khác hay hơn, nếu làm được điều này thì sẽ tuyệt vời đối với những danh sách dài vài chục nghìn dòng mà tốc độ vẫn nhanh. ý tưởng code như vậy có nhanh không anh, tầm 1 ngày hoặc 2 ngày có xong được không anh, anh nghĩ code sẽ ngắn chứ?
 
Upvote 0
Trước giờ mình chỉ biết cách lọc trên mảng, không nghĩ là có những cách khác hay hơn, nếu làm được điều này thì sẽ tuyệt vời đối với những danh sách dài vài chục nghìn dòng mà tốc độ vẫn nhanh. ý tưởng code như vậy có nhanh không anh, tầm 1 ngày hoặc 2 ngày có xong được không anh, anh nghĩ code sẽ ngắn chứ?
Vẫn lọc duyệt trên mảng nhưng bằng phương thức khác, code thì dài dòng văn tự, nhưng nó rất nhanh đối với công cụ tìm kiếm bằng combobox, bởi cứ mỗi sự kiện change ta gõ 1 ký tự thì nó lọc một công đoạn, cho nên nó sẽ rất nhanh so với các kiểu duyệt lọc thông thường khác.
 
Upvote 0
Vẫn lọc duyệt trên mảng nhưng bằng phương thức khác, code thì dài dòng văn tự, nhưng nó rất nhanh đối với công cụ tìm kiếm bằng combobox, bởi cứ mỗi sự kiện change ta gõ 1 ký tự thì nó lọc một công đoạn, cho nên nó sẽ rất nhanh so với các kiểu duyệt lọc thông thường khác.
Kiểu như dùng nâng cao của mảng? Có cách nào để áp dụng luôn sáng tìm trên textbox và hiện ra trên listbox để có tốc độ cực nhanh?
 
Upvote 0
Kiểu như dùng nâng cao của mảng? Có cách nào để áp dụng luôn sáng tìm trên textbox và hiện ra trên listbox để có tốc độ cực nhanh?
Đừng tìm kiếm bằng TextBox và cho kết quả trên ListBox, tôi nhớ trước đây có tranh luận về vấn đề này rồi, đó là một vấn đề tạo control trên sheet nó phát sinh lỗi (để tìm lại không nhớ nó nằm ở đâu).
Tại sao tôi khuyến khích tìm kiếm trên ComboBox? Bởi vì nó như là một sản phẩm được kết cấu vừa là TextBox và ListBox kết hợp lại thành một cho nên sử dụng nó như sử dụng 2 control mà nó sẽ không bị lỗi. Nó chỉ khác ListBox một chỗ là không được chọn nhiều mục một lúc.
 
Upvote 0
Đừng tìm kiếm bằng TextBox và cho kết quả trên ListBox, tôi nhớ trước đây có tranh luận về vấn đề này rồi, đó là một vấn đề tạo control trên sheet nó phát sinh lỗi (để tìm lại không nhớ nó nằm ở đâu).
Tại sao tôi khuyến khích tìm kiếm trên ComboBox? Bởi vì nó như là một sản phẩm được kết cấu vừa là TextBox và ListBox kết hợp lại thành một cho nên sử dụng nó như sử dụng 2 control mà nó sẽ không bị lỗi. Nó chỉ khác ListBox một chỗ là không được chọn nhiều mục một lúc.
A Nghĩa mở thớt mới thôi anh.
Một topic hay, có lẽ cắt hết các bài liên quan sang, để không ảnh hưởng đến bài của tác giả.
 
Upvote 0
A Nghĩa mở thớt mới thôi anh.
Một topic hay, có lẽ cắt hết các bài liên quan sang, để không ảnh hưởng đến bài của tác giả.
Do bạn đó hỏi thì mình trả lời, nhưng vấn đề lọc do mình phát minh chưa hoàn thiện nên không mở topic mới được. Mà thôi, không nói về nó ở đây nữa vậy.
 
Upvote 0
Nói về lọc dữ liệu trên ComboBox bằng array để tìm mục nào đó thì mình mới phát minh ra một kiểu lọc mà từ trước tới nay chưa một ai có thuật toán như mình, nó đảm bảo nhanh từ bằng đến gấp đôi gấp ba và nhiều hơn thế nữa nếu cứ tăng 1 ký tự! Nhưng mình đang hoàn thiện sẽ có dịp mình tặng cho mọi người cùng thưởng thức!

Lúc trước tôi cũng có viết mấy kiểu lọc dữ liệu "của comboBox". Ngoài mục tiêu giúp người dùng tìm nhanh còn có mục tiêu giảm tải lượng dữ liệu truyền tải nếu áp dụng cho các ứng dụng lấy dữ liệu qua internet (SQL Server).




 
Lần chỉnh sửa cuối:
Upvote 0
Lúc trước tôi cũng có viết mấy kiểu lọc dữ liệu "của comboBox". Ngoài mục tiêu giúp người dùng tìm nhanh còn có mục tiêu giảm tải lượng dữ liệu truyền tải nếu áp dụng cho các ứng dụng lấy dữ liệu qua internet (SQL Server).
Thì mình cũng lấy dữ liệu từ Access lên Excel rồi lọc dữ liệu qua ComboBox:

 
Upvote 0
Lúc nào đó phải học mấy bác chiêu này, thấy hay quá
 
Upvote 0
Đừng tìm kiếm bằng TextBox và cho kết quả trên ListBox, tôi nhớ trước đây có tranh luận về vấn đề này rồi, đó là một vấn đề tạo control trên sheet nó phát sinh lỗi (để tìm lại không nhớ nó nằm ở đâu).
Tại sao tôi khuyến khích tìm kiếm trên ComboBox? Bởi vì nó như là một sản phẩm được kết cấu vừa là TextBox và ListBox kết hợp lại thành một cho nên sử dụng nó như sử dụng 2 control mà nó sẽ không bị lỗi. Nó chỉ khác ListBox một chỗ là không được chọn nhiều mục một lúc.
Anh xem thêm về cách lọc bằng textbox và kết quả là listbox Bài này nhé
 
Upvote 0
đoán thôi chứ chưa chắc lắm ... hình như Rs.Filter thuần ADODB nó nhanh hơn cho vào 1 Array xong lọc nó

Nếu lọc = 1 Array data trên Sheet thì may ra nhanh còn Data Ở Files khác chắc thua quá
 
Upvote 0
Chào hai sếp, hai sếp làm ơn có thể cho em xin file kèm này tham khảo được không?
Các sếp nói chuyện với nhau em thấy hay quá nhưng em không hiểu gì hết.
Nếu ý bạn là hỏi về đoạn mà bạn trích của Hai Lúa Miền Tây thì tôi đã viết nhiều lần rồi.

Giả sử bạn có mảng 2 chiều Arr "bình thường" với nghĩa là dòng và cột của nó y hệt như dòng và cột mà bạn cần nhập vào ListBox, ComboBox. Lúc đó bạn nhập mảng đó vào ListBox, ComboBox bằng thuộc tính LIST
Mã:
ListBox1.List = Arr
ComboBox1.List = Arr
Nếu Arr là mảng "đảo ngược", "xoay 90 độ" so với mảng cần nhập vào ListBox, ComboBox thì bạn dùng thuộc tính COLUMN
Mã:
ListBox1.Column = Arr
ComboBox1.Column = Arr
Nhiều người không biết dùng Column nên khi có mảng Arr "xoay 90 độ" thì họ dùng vòng For để từ mảng Arr tạo ra mảng mới vd. ketqua là mảng "bình thường", rồi dùng thuộc tính List để nhập vào ListBox, ComboBox
Mã:
ListBox1.List = ketqua
ComboBox1.List = ketqua
 
Upvote 0
Nếu ý bạn là hỏi về đoạn mà bạn trích của Hai Lúa Miền Tây thì tôi đã viết nhiều lần rồi.

Giả sử bạn có mảng 2 chiều Arr "bình thường" với nghĩa là dòng và cột của nó y hệt như dòng và cột mà bạn cần nhập vào ListBox, ComboBox. Lúc đó bạn nhập mảng đó vào ListBox, ComboBox bằng thuộc tính LIST
Mã:
ListBox1.List = Arr
ComboBox1.List = Arr
Nếu Arr là mảng "đảo ngược", "xoay 90 độ" so với mảng cần nhập vào ListBox, ComboBox thì bạn dùng thuộc tính COLUMN
Mã:
ListBox1.Column = Arr
ComboBox1.Column = Arr
Nhiều người không biết dùng Column nên khi có mảng Arr "xoay 90 độ" thì họ dùng vòng For để từ mảng Arr tạo ra mảng mới vd. ketqua là mảng "bình thường", rồi dùng thuộc tính List để nhập vào ListBox, ComboBox
Mã:
ListBox1.List = ketqua
ComboBox1.List = ketqua
Sếp Nghĩa đã phớt lờ cháu rồi, giờ chỉ chú lả để ý đến cháu, cảm ơn chú rất nhiều.
Cháu sẽ đọc lại thêm mấy lần nữa xem có ngấm thêm được ít nào không.
 
Upvote 0
Sếp Nghĩa đã phớt lờ cháu rồi, giờ chỉ chú lả để ý đến cháu, cảm ơn chú rất nhiều.
Cháu sẽ đọc lại thêm mấy lần nữa xem có ngấm thêm được ít nào không.
Những gì bạn hỏi đều rất cao hơn trình độ của bạn, nếu có đưa bạn xem bạn chỉ ngó rồi để đó. Còn những bài của batman1 còn cao hơn, tôi đọc còn chỉ biết ngó luôn chứ bạn sao đọc nổi!
 
Upvote 0
Những gì bạn hỏi đều rất cao hơn trình độ của bạn, nếu có đưa bạn xem bạn chỉ ngó rồi để đó. Còn những bài của batman1 còn cao hơn, tôi đọc còn chỉ biết ngó luôn chứ bạn sao đọc nổi!
Cảm ơn sếp đã cho em lời khuyên, em tưởng sêp tiếp em xong sợ em bám càng đòi 2 bà Trưng và bà Tân Vlốc.
Em không hiểu nên không hỏi, chỉ xin file kèm xem mục đích khi chạy nó ra làm sao, nếu nó hữu ích cho em thì lúc đó em mới hỏi từng bước.
 
Upvote 0
Sếp Nghĩa đã phớt lờ cháu rồi, giờ chỉ chú lả để ý đến cháu, cảm ơn chú rất nhiều.
Cháu sẽ đọc lại thêm mấy lần nữa xem có ngấm thêm được ít nào không.
Có gì mà ngấm.
Tạo tập tin mới có UserForm với 2 ListBox (có 2 cột). Dữ liệu như trên hình, code cũng như trong hình.

Tại sao tại (A) dùng LIST mà ở (B) lại dùng COLUMN?

Mảng Arr tại (A) có dòng cột y như cần phải có trong ListBox1 nên để load vào ListBox1 thì phải dùng LIST.

Mảng Arr tại (B) có dòng cột "xoay 90 độ" so với cần phải có trong ListBox2 nên để load vào ListBox2 thì phải dùng COLUMN.

Thường mảng Arr "xoay 90 độ" so với nhu cầu cần phải có được tạo bởi code và từng "ô" của nó được điền bằng code từ những giá trị nào đó. Khi đó những người không biết dùng COLUMN thì họ dùng
Mã:
ListBox2.List = Application.WorksheetFunction.Transpose(Arr)

Nhưng do nhiều khi Transpose có lỗi nên để dùng LIST họ phải tạo mảng mới ketqua từ Arr rồi dùng LIST

listcolumn.jpg
 
Upvote 0

Bài viết mới nhất

Back
Top Bottom