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

Chia sẻ bởi:hands
★★★★★
Quảng cáo

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:

Sub GetDataByOpenFile()
Dim Wb As Workbook, WbS As Workbook
Dim sFullName$, tmr#

tmr = Timer()
Application.ScreenUpdating = False
sFullName = "D:GoogleDrive2CaNhanVBAMapVN.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:

Sub GetDataByADODB()
Dim Rec As Object, rs As Object
Dim sFullName$, iCol&, tmr#

tmr = Timer()
sFullName = "D:GoogleDrive2CaNhanVBAMapVN.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:

[I]#If VBA7 Then[/I]

[I]Private Declare PtrSafe Function SetLocaleInfo _[/I]

[I]Lib "kernel32" Alias "SetLocaleInfoA" ( _[/I]

[I]ByVal Locale As LongPtr, _[/I]

[I]ByVal LCType As LongPtr, _[/I]

[I]ByVal lpLCData As String) As Boolean[/I]

[I]Private Declare PtrSafe Function GetUserDefaultLCID% Lib "kernel32" ()

#Else[/I]

[I]Private Declare Function SetLocaleInfo _[/I]

[I]Lib "kernel32" Alias "SetLocaleInfoA" ( _[/I]

[I]ByVal Locale As Long, _[/I]

[I]ByVal LCType As Long, _[/I]

[I]ByVal lpLCData As String) As Boolean[/I]

[I]Private Declare Function GetUserDefaultLCID% Lib "kernel32" ()

#End If[/I]

[I]Private Const LOCALE_SDECIMAL = &HE[/I]

[I]Private Function SetLocalSetting(LC_CONST As Long, Setting As String) As Boolean[/I]

[I]Call SetLocaleInfo(GetUserDefaultLCID(), LC_CONST, Setting)[/I]

[I]End Function[/I]

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:

[URL='www.giaiphapexcel.com/diendan/threads/d%C3%B9ng-macro-4-%C4%91%E1%BB%83-l%E1%BA%A5y-d%E1%BB%AF-li%E1%BB%87u-t%E1%BB%AB-1-file-%C4%91ang-%C4%91%C3%B3ng.39312/']www.giaiphapexcel.com/diendan/threads/dùng-macro-4-để-lấy-dữ-liệu-từ-1-file-đang-đóng.39312/

Sub GetDataByMacro4()
Dim tmr#
tmr = Timer()
  Dim sFile As String, sSheet As String, sAddr As String
  sFile = "D:GoogleDrive2CaNhanVBAMapVN.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.

www.giaiphapexcel.com/diendan/threads/so-s%C3%A1nh-3-c%C3%A1ch-l%E1%BA%A5y-d%E1%BB%AF-li%E1%BB%87u-t%E1%BB%AB-1-file-%C4%91ang-%C4%91%C3%B3ng.157352/page-4#post-1043424

Học Nhân sự Tổng hợp – Trở thành chiến binh nhân sự vững nghiệp vụ
Khóa học SprinGO phù hợp

Học Nhân sự Tổng hợp – Trở thành chiến binh nhân sự vững nghiệp vụ

Con người là một trong những yếu tố quan trọng của công ty, là tài sản quý giá của doanh nghiệp. Chính vì thế,...

Xem khóa học
★★★★★ 5 ★ 1 👤 7 ▥ 0
Quảng cáo

Bạn nên đọc

7 Responses

  1. hands says:

    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.
    http://www.giaiphapexcel.com/diendan/threads/t%E1%BB%95ng-h%E1%BB%A3p-n-1-files-trong-folder-kh%C3%B4ng-s%E1%BB%AD-d%E1%BB%A5ng-ado-dao-v%C3%A0-workbooks-open.115535/

    Đọ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

    để 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ì

    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

    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

    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

    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à

    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 : drive.google.com/file/d/1MgTowNES3NT3D1g6H8MMPPsqP1qa_FW-/view
    23222321

    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 ạ

    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: http://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à!

    Làm thử dữ liệu trên Access rồi kết nối qua Excel xem nó bao nhiêu giây bằng ADO.

    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?

  2. hands says:

    … 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.

    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.

    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.

    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?

    Ah,
    Tôi cũng học từ sư phụ @NDU
    Code bài #19, dùng hàm Getdata thôi
    http://www.giaiphapexcel.com/diendan/threads/import-d%E1%BB%AF-li%E1%BB%87u.86477/page-1

    Vậy thì dùng ADO mới là vô địch. Tặng bạn 2 code này:

    Function GetData(ByVal FileName As String, Optional ByVal SheetName As String = "", Optional ByVal RangeAddress As String = "")
    
    Dim cnn As Object, rsData As Object
      Dim tmpArr, arr
      Dim szConn As String, szSQL As String, tmp As String
      Dim lR As Long, lC As Long, lVersn As Long
      On Error GoTo ErrHandler
      lVersn = Val(Application.Version)
      Set cnn = CreateObject("ADODB.Connection")
      Set rsData = CreateObject("ADODB.Recordset")
    
    If lVersn < 12 Then
        szConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FileName & ";" & _
                    "Extended Properties=""Excel 8.0;HDR=No"";IMEX=1;"
      Else
        szConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & FileName & ";" & _
                    "Extended Properties=""Excel 12.0;HDR=No;IMEX=1"";"
      End If
      If SheetName = "" Then
        Dim Dbs  As Object, db As Object
        Set Dbs = CreateObject("DAO.DBEngine." & IIf(lVersn < 12, "36", "120"))
        Set db = Dbs.OpenDatabase(FileName, False, False, "Excel 8.0;")
        tmp = db.TableDefs(0).Name
        tmp = Replace(tmp, "''", "'")
        SheetName = tmp
        db.Close
        Set Dbs = Nothing: Set db = Nothing
      Else
        SheetName = SheetName & "$"
      End If
      cnn.Open szConn
      szSQL = "SELECT * FROM [" & SheetName & RangeAddress & "];"
      rsData.Open szSQL, cnn, 1, 1
      tmpArr = rsData.GetRows
      ReDim arr(UBound(tmpArr, 2), UBound(tmpArr, 1))
      rsData.Close: cnn.Close
      For lR = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        For lC = LBound(tmpArr, 1) To UBound(tmpArr, 1)
          arr(lR, lC) = tmpArr(lC, lR)
        Next
      Next
      GetData = arr
      Set rsData = Nothing: Set cnn = Nothing
      Exit Function
    ErrHandler:
      MsgBox Err.Description
      Set rsData = Nothing: Set cnn = Nothing
    End Function
    Sub GetDataFromRS(ByVal Target As Range, ByVal FileName As String, Optional ByVal SheetName As String = "", Optional ByVal RangeAddress As String = "")
    
    Dim cnn As Object, rsData As Object
      Dim szConn As String, szSQL As String, tmp As String
      Dim lR As Long, lC As Long, lVersn As Long
      On Error GoTo ErrHandler
      lVersn = Val(Application.Version)
      Set cnn = CreateObject("ADODB.Connection")
      Set rsData = CreateObject("ADODB.Recordset")
    
    If lVersn < 12 Then
        szConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FileName & ";" & _
                    "Extended Properties=""Excel 8.0;HDR=No"";IMEX=1;"
      Else
        szConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & FileName & ";" & _
                    "Extended Properties=""Excel 12.0;HDR=No;IMEX=1"";"
      End If
    
    If SheetName = "" Then
        Dim Dbs  As Object, db As Object
        Set Dbs = CreateObject("DAO.DBEngine." & IIf(lVersn < 12, "36", "120"))
        Set db = Dbs.OpenDatabase(FileName, False, False, "Excel 8.0;")
        tmp = db.TableDefs(0).Name
        tmp = Replace(tmp, "''", "'")
        SheetName = tmp
        db.Close
        Set Dbs = Nothing: Set db = Nothing
      Else
        SheetName = SheetName & "$"
      End If
      cnn.Open szConn
      szSQL = "SELECT * FROM [" & SheetName & RangeAddress & "]"
      'szSQL = "SELECT [F2],[F4] FROM [" & SheetName & RangeAddress & "] WHERE F1>5 AND F3 = 'ELECTRIC'"
      rsData.Open szSQL, cnn, 1, 1
      Target.CopyFromRecordset rsData
      rsData.Close: cnn.Close
      Set rsData = Nothing: Set cnn = Nothing
       MsgBox "Data has been successfully imported!"
      Exit Sub
    ErrHandler:
      MsgBox Err.Description
      Set rsData = Nothing: Set cnn = Nothing
    End Sub

    Tùy chọn xài 1 trong 2 cái nha!
    – Cả 2 cái đều có thể dùng trực tiếp trong VBA
    – Cái thứ nhất là HÀM, vậy bạn có thể gõ trực tiếp trên bảng tính
    – Cái thứ hai là SUB, vậy chỉ có thể dùng trong VBA (không gõ đươc trên bảng tính)
    ——————————-
    Phần code ở trên bạn cho vào 1 Module và cũng không cần hiểu, chỉ cần biết áp dụng là đủ
    Ví dụ: Bạn chọn áp dụng HÀM
    – File dữ liệu đang đóng nằm ở: "D:DuLieuB.xls"
    – Tên sheet của file dữ liệu là "Sheet3"
    – Vùng dữ liệu cần lấy là "C1:H10"
    – Vậy ta viết thêm code áp dụng thế này:

    Sub Main()
      Dim FileName as String, SheetName as String, RangeAddress as String
      Dim arr
      [COLOR=#ff0000]FileName = "D:DuLieuB.xls"
      SheetName = "Sheet3"
      RangeAddress = "C1:H10"[/COLOR]
      arr = GetData(FileName, SheetName, RangeAddress)
      If IsArray(arr) Then
        [COLOR=#0000cd]ThisWorkbook.Sheets(1).Range("A1")[/COLOR].Resize(UBound(arr, 1) + 1, UBound(arr, 2) + 1).Value = arr
        MsgBox "Data has been successfully imported!"
      End If
    End Sub

    Chỉ cần lưu ý 3 dòng màu đỏ, khai báo cho đúng là được
    Chổ màu xanh chính là nơi bạn cần copy đến
    Lưu ý:
    – Nếu bạn chỉ khai báo FileName, không khai báo SheetName, RangeAddress thì đồng nghĩa bạn muốn lấy toàn bộ dữ liệu của sheet đầu tiên
    – Trong Sub Main (là Sub áp dụng), phần FileName bạn có thể dùng GetOpenFileName để tùy ý chọn file nguồn. Ví dụ:

    Sub Main_OpenFileName()
      Dim arr, vFile
      [COLOR=#ff0000]vFile = Application.GetOpenFilename("Excel Files, *.xls;*.xlsx;*.xlsm")[/COLOR]
      If TypeName(vFile) = "String" Then
        arr = GetData(CStr(vFile))
        If IsArray(arr) Then
          ThisWorkbook.Sheets(1).Range("A1").Resize(UBound(arr, 1) + 1, UBound(arr, 2) + 1).Value = arr
          MsgBox "Data has been successfully imported!"
        End If
      End If
    End Sub

    Màu đỏ dùng để mở hộp chọn file. Đoạn code trên không khai báo SheetName và RangeAddress nên code sẽ lấy toàn bộ dữ liệu ở sheet đầu tiên
    ——————
    Cách dùng cho code Sub GetDataFromRS cũng gần tương tự. Bạn tự khám phá nhé

    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:

    Private Sub ComboBox1_Change()
      With ComboBox1
        .ListFillRange = ""
        .ColumnCount = 2
        .ColumnWidths = "50;100"
        .Width = "200"
        .ColumnHeads = True
        Dim lR As Long, arr
        FileName = "D:EXCELGPEData3.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

    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ề.
    2354

  3. hands says:

    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ế.

    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!

    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?
    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?

    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:

    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
           [COLOR=rgb(184, 49, 47)][B][SIZE=22px][FONT=Verdana] .MoveFirst[/FONT][/SIZE][/B][/COLOR]
            Sheet3.Range("A2").CopyFromRecordset .DataSource
        End With
    End Sub

    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.

    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.

    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 đó.

    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:

    2355

    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.

    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.

    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
    2357

    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.

    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?

  4. hands says:

    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à

    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

    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é.

    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

    ultimatedelphi.wordpress.com/2016/04/14/database-connectivity-frameworks-in-delphi/

    2356

    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.

    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
    http://www.upgrad.com/blog/data-science-programming-languages/

    à 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

  5. hands says:

    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!

    Chia luôn để mọi người sẻ xem thế nào anh Nghĩa đẹp trai ơi.

    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 …

    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.

    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.

    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.

    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?

    Anh xem thêm về cách lọc bằng textbox và kết quả là listbox [URL='www.giaiphapexcel.com/diendan/threads/khai-th%C3%A1c-v%C3%A0-t%C3%B9y-bi%E1%BA%BFn-th%C3%AAm-s%E1%BB%ADa-xu%E1%BA%A5t-file-v%C3%A0-l%E1%BA%A5y-d%E1%BB%AF-li%E1%BB%87u-t%E1%BB%AB-recordset.152924/page-8']Bài này nhé

    Đừ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.

    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).

    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

    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

    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

    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.

    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

    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

    2358

    Hình như sau một hồi đọc lại nhiều lần thì cháu đã hiểu một chút về LIST và COLUMN rồi thì phải.
    Túm lại khi lấy dữ liệu từ hình (A) và (B) nếu sử dụng chung một thuộc tính LIST hoặc COLUMN, thì một trong 2 sẽ phải dùng Transpose, nếu không muốn dùng Transpose thì phải sử dụng cả 2 thuộc tính này ứng với mỗi bảng, cháu hiểu là vậy cảm ơn chú.
    Chú hướng dẫn rất có tâm, cháu chẳng biết gì mà còn hiểu được như thế này nếu với những người biết hoặc hơi biết thì có lẽ quá rõ rồi.

  6. hands says:

    Anh cho em hỏi là dùng ADO này thì không lấy dữ liệu từ file excel đang Protect workbook for structure thì phải. Có cách nào khắc phục được không anh?
    Một vấn đề nữa là hay bị trường hợp không mở ngầm, mà lại mở lên dưới dạng ReadOnly luôn anh ạ, Code vẫn chạy bình thường nhưng gây khó chịu với mất thời gian tắt đi thôi anh. Anh giúp em với!

    1. Tôi chưa thử với trường hợp protect workbook. Để tôi thử xem thế nào rồi thông tin lại.
    2. Tôi dùng ADODB khá nhiều nhưng chưa bao giờ gặp nó mở file lên mà thấy được cả. Còn chưa hiểu cái Read Only của bạn có phải thấy được ở trạng thái ReadOnly không? Nếu đúng vậy bạn gửi tôi file nguồn và code bạn dùng để tôi xem thử mới biết được.

    Ở bài #105 hình như nói rằng "mình tự mở file".
    ADO ngày xưa có cái bug là truy vấn file đang mở có thể bị kẹt file và nếu bộ nhớ yếu thì có thể bị treo máy (chỉ "có thể" thôi, không phải lúc nào cũng xảy ra). Bug này tôi đã đề cập trước đây khá lâu.
    Hình như qua Office 1013 thì Microsoft đã khắc phục vấn đề này.

    Vậy nhờ anh thử giúp em với ạ. Còn cái code ADO đó em tùy biến từ file của thầy Ndu ở bài viết hồi 2017 hay sao đó ạ. Sau đó em chạy lại file của thầy luôn, nhưng vẫn bị anh.
    Theo em thấy thì thường bị khi có file excel khác bất kỳ đang mở, hoặc đang có 1 file được preview ở folder nào đó ạ. sau đó em tắt hết excel và mở lại thì nó lại bình thường anh.

    Hình như qua Office 1013 thì Microsoft đã khắc phục vấn đề này.

    Em sử dụng excel 2016 ạ, không biết có cách nào không ạ?

    Nếu đúng vậy bạn gửi tôi file nguồn và code bạn dùng để tôi xem thử mới biết được.

    Em dùng thử file của trên GPE luôn thì vẫn có lúc bị ạ
    http://www.giaiphapexcel.com/diendan/threads/t%E1%BB%95ng-h%E1%BB%A3p-d%E1%BB%AF-li%E1%BB%87u-t%E1%BB%AB-nhi%E1%BB%81u-file-excel-v%C3%A0o-1-file-kh%C3%B4ng-c%E1%BA%A7n-m%E1%BB%9F-file.122039/page-3#posts

    File Protect Workbook for structure có mật khẩu thì câu: "Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    sửa thành: "Extended Properties=""Excel 12.0 Xml;HDR=YES;PWD=123"";"

    (123 là mật khẩu protect)

    Anh cho em hỏi là dùng ADO này thì không lấy dữ liệu từ file excel đang Protect workbook for structure thì phải. Có cách nào khắc phục được không anh?
    Một vấn đề nữa là hay bị trường hợp không mở ngầm, mà lại mở lên dưới dạng ReadOnly luôn anh ạ, Code vẫn chạy bình thường nhưng gây khó chịu với mất thời gian tắt đi thôi anh. Anh giúp em với!

    1. Tôi vừa có thử Protect workbook for structure và import thì vẫn bình thường bạn. không có lỗi gì.
    2. Hay trường hợp không mở ngầm? tôi chưa hiểu ý này?

    Người hỏi có giải thích trường hợp ở bài #107: có file Excel đang mở.
    Theo tôi nhớ thì do lỗi ADO bị chạm resource connection. Bug này ai chơi Resource Consumption qua mấy cái OLE đều biết. Bug này nếu Microsoft chưa khắc phục thì chịu thôi.

    1. Tôi vừa có thử Protect workbook for structure và import thì vẫn bình thường bạn. không có lỗi gì.
    2. Hay trường hợp không mở ngầm? tôi chưa hiểu ý này?

    Với code ở bài #1 thì buộc phải thêm PWD=123 mới chạy được. Còn code kiểu này thì không cần (tôi thực hành thôi chứ không biết lý do)

    Set Rec = CreateObject("ADODB.Connection")
        With Rec
            .Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & sFullName & ";Extended Properties=""Excel 12.0;HDR=YES"""
            Sheet3.Range("A2").CopyFromRecordset .Execute("Select TEN, SOLG From [Sheet1$]")
        End With

    P/S: sau khi đã cung cấp mật khẩu 1 lần không đóng Excel thì bỏ PWD=123 đi nó chạy được (lý do: không biết), chứ không phải do cú pháp tôi nói ở trên.

  7. hands says:

    Người hỏi có giải thích trường hợp ở bài #107: có file Excel đang mở.
    Theo tôi nhớ thì do lỗi ADO bị chạm resource connection. Bug này ai chơi Resource Consumption qua mấy cái OLE đều biết. Bug này nếu Microsoft chưa khắc phục thì chịu thôi.

    Hic, vậy là bó tay anh nhỉ? vì vấn đề này mà em cũng đang suy nghĩ chuyển qua Power Query. Sẵn cho em hỏi tốc độ như nào so với ADO nhỉ?.
    Em gồm 12 file, mỗi file 1 sheet gồm khoảng 3000 dòng và 9 cột ạ

    Bạn thử power query xem sao, chắc là sẽ không thất vọng đâu.
    Có thể chậm nhưng chắc.
    Ngoài ra PQ tổng hợp tính toán ngon lành.

    Tôi mà làm việc với dữ liệu lớn, cần PQry, PBi thì tôi học ngay. Bạn @Haffaz Aladeen có lẽ nên học là vừa.

    Tính tôi là học mà không thấy trước mắt được gì thì tôi không học được (chứ không phải là không thèm học)
    ……………………………………………………………………………………….. $$$$@

    Trước mắt là bạn có thể bổ sung thêm một cách import dữ liệu ngay tại topic này đó thôi.
    PQ là 1 tool của excel, thử đọc tài liệu của sư phụ @ptm0412 phần cơ bản là giải quyết được nhiều thứ lắm rồi.

    Tôi nói là đời thực bạn ơi. Tôi học được VBA là do nó liên quan đến công việc, cơm áo gạo tiền của tôi. Việc đến đâu học đến đó thôi chứ không nâng tầm được. Nên chừ thì có gì xài nấy thôi (may mà còn có thứ để xài –=0 )

    GPE này rất thực mà bạn.
    PQ không đơn thuần là lấy dữ liệu về. PQ có thể tính toán, tổng hợp, group by, insert thêm trường… nếu dùng ADO chắc sẽ mệt lắm.

    Nếu bạn thích code VBA thì cứ giữ vậy.
    Nếu bạn muốn bước qua lĩnh vực Query thì nên học cái nhóm Power BI.
    Ưu điẻm của 'thực' là nó … thực.
    Khuyết điểm của 'thực', trong môi trường làm việc ở VN, là nó quá cứng nhắc theo guồng máy của VN.

    Tôi đã từng nhiều lần nhắc nhỏ, như cái đĩa hát cũ, là làm việc kiểu này là chạy theo dữ liệu chứ không làm chủ nó. (*1)

    BI là Business Intelligence, nó ngầm chứa điều kiện trích xuất và phân tích dữ liệu theo dạng cube (nhiều mặt, đa chiều). Dữ liệu chứa trong bảng tính Excel là một mặt, hai chiều, những cái vặn vẹo qua VBA chỉ tối đa giúp cho lắp thêm vây cánh cho Excel một cách cứng nhắc. Code VBA có thể thêm mặt nhìn, thêm chiều, nhưng muốn nó uyển chuyển thì cái project VBA phải lớn tổ bố. Viết cái project tổ bố thì thà học Power Query khoẻ hơn.

    (*1) nếu bạn chỉ vì cơm gạo thì thoi. Nhưng nếu muốn có chút thoải mái (tôi tránh dùng từ 'đam mê') thì làm chủ được dữ liệu sẽ thấy cái đẹp, cái hay của chúng, và sẽ thấy thoải mái với công việc thiết kế những dạng bảng tính 'xịn'.

    Mỗi môn đều có cái hay. Nếu có một cơ sở dữ liệu chuẩn thì dùng Power Query quá tuyệt, phân tích dữ liệu, sắp xếp tổng hợp dữ liệu lớn, thiết lập các mối quan hệ…
    Còn nhiều khi với dữ liệu chưa chuẩn lắm, dùng VBA lại uyển chuyển, mà ngôn ngữ em thấy cũng dễ hiểu, cho kết quả nhanh, các báo cáo tùy biến theo nhu cầu
    Nên hiện tại em vẫn kết hợp cả hai trong công việc.

    Mỗi môn đều có cái hay. Nếu có một cơ sở dữ liệu chuẩn thì dùng Power Query quá tuyệt {1}, phân tích dữ liệu, sắp xếp tổng hợp dữ liệu lớn, thiết lập các mối quan hệ…
    Còn nhiều khi với dữ liệu chưa chuẩn lắm, dùng VBA lại uyển chuyển {2}, mà ngôn ngữ em thấy cũng dễ hiểu, cho kết quả nhanh, các báo cáo tùy biến theo nhu cầu
    Nên hiện tại em vẫn kết hợp cả hai trong công việc.

    {1} tôi nhường cho các bạn đã rành Power Query trả lời câu này

    {2} Đó chính là câu "chạy theo dữ liệu"

    {1} Tất nhiên là Power Query cũng có thể làm sạch dữ liệu, em cũng có theo dõi nhiều bài trên GPE, việc làm sạch cũng cần phải có kiến thức nhất định, không thì làm mãi không thấy sạch.

    Tôi nghĩ cái món Vba ở đây trên 90% tham gia gpe xem nó như kim chỉ nam rồi, nghĩ nó là nhất rồi thì đâu biết cái khác nó hay nó dở thế nào đâu. Làm cái nhỏ nhỏ thì được. Còn dữ liệu lớn thì nên tìm giải pháp khác. Tôi thấy một số thứ viết vba mướt mồ hôi còn dùng power bi, tableau, python, đại loại rất nhiều thứ xử lý rất đơn giản, nhanh gọn. Biết nhiều càng tốt nhưng đừng cuồng quá một thứ. Tôi nghĩ vậy

    Vì đây là giải pháp excel mà bạn! Và nó phù hợp với đa số mới phố thông excel. Chuyện nâng cao hoặc các ngôn ngữ khác ưu việt hơn có mấy người rành để bàn tới.

    Tôi nghĩ cái món Vba ở đây trên 90% tham gia gpe xem nó như kim chỉ nam rồi, nghĩ nó là nhất rồi thì đâu biết cái khác nó hay nó dở thế nào đâu. Làm cái nhỏ nhỏ thì được. Còn dữ liệu lớn thì nên tìm giải pháp khác. Tôi thấy một số thứ viết vba mướt mồ hôi còn dùng power bi, tableau, python, đại loại rất nhiều thứ xử lý rất đơn giản, nhanh gọn. Biết nhiều càng tốt nhưng đừng cuồng quá một thứ. Tôi nghĩ vậy

    Tôi không tranh luận về việc bị giới hạn nguồn lực. Ý tôi là không nên quá thụ động vào một thứ. Giải quyết vấn đề thì có nhiều cách, ta nên tiếp thu cách mà giúp ta tăng hiệu suất, tiết kiệm thời gian. Tôi nhận thấy các công cụ BI, nó giúp nhiều cho người sử dụng, một số hoạt động cơ bản chỉ cần kéo, thả ví dụ như distinct, sum, average,min, max, count…, công cụ Q&A nó còn tự động phân tích một số thứ dựa trên dataset, và nó sẽ gợi ý cho người sử dụng nếu cần thì chỉ cần kéo thả. Chốt lại thì nên chọn cái nào nhanh gọn, tiết kiệm thời gian, tăng hiệu suất mà không phải mất quá nhiều công sức. Còn ai thấy đủ mà không cần phải thay đổi thì cũng đâu có sao đâu, miễn hài lòng là được rồi.

    Biết càng nhiều càng tốt, vì kiến thức không bao giờ đủ. Nhưng tôi nghĩ số người dùng dữ liệu khủng chỉ là thiểu số. Mà dù thiểu số hay đa số thì cũng có người chỉ làm việc với dữ liệu bình thường. Nếu kiến thức hiện có đủ để làm việc với dữ liệu đó thì khó khuyên họ học cái mới. Vì họ chưa phải làm việc với dữ liệu khủng, sau giờ làm việc nếu có thời gian thì họ muốn giúp vợ / chồng việc nhà, chăm sóc con, trau dồi những kỹ năng khác cấp bách hơn. Nhu cầu có rất nhiều, không đủ thời gian thì phải lựa chọn thôi. Với bạn là phải đầu tư cho cái này, người khác họ có ưu tiên khác.

Leave a Reply

Your email address will not be published. Required fields are marked *

Quảng cáo

Cũ vẫn chất

Xem thêm