So sánh 3 cách lấy dữ liệu từ 1 file đang đóng

Liên hệ QC

Maika8008

Thành viên gạo cội
Tham gia
12/6/20
Bài viết
4,741
Được thích
5,669
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

  • MapVN.xlsx
    660.4 KB · Đọc: 55
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
Web KT
Back
Top Bottom