Sử dụng ADO để copy dữ liệu từ file này sang file khác

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

Mình có 2 file cùng nằm trong 1 thư mục : Nguon.xlsm và Dich.xlsm
Trong file: Nguon.xlsm . Ta có vùng dữ liệu cần cập nhật , gồm 242 cột (từ cột "AB" đến cột "JI") , bắt đầu từ dòng 35 đến dòng cuối cùng trong cột "AB"
File : Dich.xlsm cũng có cấu trúc tương tự . Mình xin code để thực hiện công việc :
Thứ 1 : "Cập nhật vùng dữ liệu từ file : Nguon.xlsm đến Dich.xlsm bằng ADO (chỉ phần dữ liệu , bỏ qua phần tiêu đề)"
Thứ 2 : Sau khi cập nhật xong , thì chạy 1 marco trên file: Dich.xlsm (để xác nhận nội dung đã được làm mới chẳn hạn)
Xin các bạn quan tâm giúp đỡ, xin cám ơn+-+-+-++-+-+-++-+-+-+

Bạn sử dụng Code sau

Option Explicit
Sub Update()
    On Error GoTo Handle
    Dim cnn As Object, lsSQL As String, lrs As Object, FileFullName As String
    Set cnn = CreateObject("ADODB.Connection")
    Set lrs = CreateObject("ADODB.Recordset")
    FileFullName = Application.ThisWorkbook.Path & "Nguon.xlsm"
    With cnn
        .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" _
                & "Data Source=" & FileFullName _
                & ";Extended Properties=""Excel 12.0;HDR=No"";"
        .Open
    End With
    lsSQL = "Select * From [CSDL$AB35:IJ100000] Where f1 Is Not Null"
    lrs.Open lsSQL, cnn, 3, 1
    If Sheets("SP").[AB35] = "" Then
        Sheets("SP").Range("AB35").CopyFromRecordset lrs
    Else
        Sheets("SP").Range("AB35").End(xlDown).Offset(1, 0).CopyFromRecordset lrs
    End If
    MsgBox "Da Update CSDL", vbInformation
    Set lrs = Nothing
    cnn.Close: Set cnn = Nothing
    Exit Sub
Handle:
    MsgBox Err.Description
End Sub

www.giaiphapexcel.com/diendan/threads/s%E1%BB%AD-d%E1%BB%A5ng-ado-%C4%91%E1%BB%83-copy-d%E1%BB%AF-li%E1%BB%87u-t%E1%BB%AB-file-n%C3%A0y-sang-file-kh%C3%A1c.82596/

Ứng dụng AI và Chat GPT trong Quản trị nhân sự
Khóa học SprinGO phù hợp

Ứng dụng AI và Chat GPT trong Quản trị nhân sự

Học xong khóa này, học viên có thể: Hiểu đúng bản chất AI, các nhóm AI phổ biến và cách AI “hoạt động” ở...

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

Bạn nên đọc

5 Responses

  1. hands says:
    From [CSDL$AB35:IJ[COLOR=#ff0000]100000[/COLOR]]

    Ở đây dòng , dòng cuối cùng không thể xác định là 100000 được vì tuỳ vào phát sinh trong khi sử dụng

    MsgBox "Da Update CSDL", vbInformation

    Ở đây là một thủ tục nằm trên file: Dich.xlsm để thực hiện thao tác tạo file: Dich.xlsm thành file: USM.xlam . Thủ tục này giúp ta thực hiện 1 công việc khác . Trong bài mình chỉnh minh hoạ là xuất thông báo thôi

    [COLOR=#ff0000]If[/COLOR] Sheets("SP").[AB35] = "" Then         Sheets("SP").Range("AB35").CopyFromRecordset lrs     Else         Sheets("SP").Range("AB35").End(xlDown).Offset(1, 0).CopyFromRecordset lrs     End If

    Ở đây mình , mình chỉ cập nhật giá trị trên file : Nguon.xlsm sang file: Dich.xlsm . Nên việc
    xét Sheets("SP"). = "" là không cần thiết . Nguồn thay đổi sao thì Đích thay đổi thế

    Có vẻ như bạn biết ADO?
    Mình sẽ không chỉnh sửa một dòng Code nào cả, chỉ nêu ra 1 số vấn đề bạn thắc mắc
    1/

    [COLOR=#000000]Ở đây dòng , dòng cuối cùng không thể xác định là 100000 được vì tuỳ vào phát sinh trong khi sử dụng[/COLOR]

    Bạn hiểu CSDL thì cấu trúc như thế nào?

    lsSQL = "Select * From [CSDL$AB35:IJ100000] [COLOR=#ff0000]Where f1 Is Not Null[/COLOR]

    Đoạn màu đỏ có ý nghĩa gì?
    2/

    [COLOR=#000000]Ở đây là một thủ tục nằm trên file: Dich.xlsm để thực hiện thao tác tạo file: Dich.xlsm thành file: USM.xlam . Thủ tục này giúp ta thực hiện 1 công việc khác . Trong bài mình chỉnh minh hoạ là xuất thông báo thôi[/COLOR]

    Cái này nằm ngoài khả năng của mình vì mình không được đào tạo và cũng không tìm kiếm được thông tin phát sinh hay gì gì đó trong suy nghĩ của bạn.
    3/

    [COLOR=#000000]Ở đây mình , mình chỉ cập nhật giá trị trên file : Nguon.xlsm sang file: Dich.xlsm . Nên việc
    xét [/COLOR][COLOR=#ff0000]Sheets("SP").[AB35] = ""[/COLOR][COLOR=#000000] là không cần thiết . Nguồn thay đổi sao thì Đích thay đổi thế[/COLOR]

    Bạn đưa ra yêu cầu là

    Sử dụng ADO để copy dữ liệu từ file này sang file khác

    Nên mình chỉ hiểu là bạn muốn Copy dữ liệu qua File khi chạy Macro không biết "thâm ý" phía sau của bạn là gì cả. Và để giải quyết "suy đoán riêng của mình" mình đã đưa ra giải pháp =>bạn hiểu và bạn có thể thay đổi phải không?

    Cuối cùng: Chúc bạn tìm được giải pháp tốt nhất nhé!
    Chào tạm biệt!

    Xin lỗi có lẽ Bạn hiểu lầm ý mình rồi . Mình chẳng hiểu gì về ADO cả mà chỉ biết chút ít về VBA thôi nên suy nghĩ của mình cũng dự trên VBA . Ví dụ đoạn :

    [CSDL$AB35:IJ100000]

    trong VBA mình hiểu : "Chỉ định 1 vùng Range("AB35:IJ100000") trong sheets("CSDL")
    còn trong câu lệnh SQL :

    lsSQL = "Select * From [CSDL$AB35:IJ100000] [COLOR=#ff0000]Where f1 Is Not Null[/COLOR]

    thì có ý nghĩ khác , mà mình lại không biết . Nên mới gây ra hiểu lầm mong bạn thông cảm cho đừng để trong lòng

    Còn phần : Thủ tục trên file: Dich.xlsm để thực hiện công việc khác . Nhưng do không liên quan đến nội dung chính (dùng ADO để copy dữ liệu) nên mình không đề cập để tránh làm rối vấn đề . Mình đợi sau khi giải quyết vấn đề chính xong , nếu mình không làm được thủ tục đó thì hỏi thêm như thế sẽ làm rõ từng vấn đề tiện giải quyết

    Còn phần : tại sao mình đặt vấn đề là "Dùng ADO để copy dữ liệu" mà trong bài viết lại ghi "Cập nhật giá trị trên file" cài này cũng do mình không biết về ADO mà biết chút ít về VBA . Ví dụ :

    If Sheets("SP").[AB35] = "" Then      Sheets("SP").Range("AB35").CopyFromRecordset lrs Else     Sheets("SP").Range("AB35").End(xlDown).Offset(1, 0).CopyFromRecordset lrs End If

    Nếu trong VBA mình hiểu là cần xét đk range("AB35") có rỗng không để thi hành dòng lệnh , mà vấn đề của mình là copy nên không không cần xét .

    Nói tóm lại , do mình không hiểu code trong ADO nên ghi ra hiểu lầm , mình xin đính chính lại . Nếu không rõ mình có thể nói thêm , mong bạn hiểu và thông cảm . Cám ơn sự quan tâm và giúp đỡ của bạn , mong sớm nhận được sự quan tâm của bạn , xin cám ơn +-+-+-++-+-+-++-+-+-+
    Khi chạy xuất hiện thông báo lỗi , bạn xem dùm nhé 1
    2838

    Chỉ tham chiếu đến 65536 dòng thôi bạn.

    Anh HLMT em đã Test trên Office 2007 không xảy ra bất kỳ lỗi gì, Office 2007 có số dòng > 65536 thì việc đặt 100000 dòng có thể gây lỗi không anh? Dữ liệu biến đổi, Version Office thay đổi, Convert Ex 2007 => 2003 ..v.v.. không thể lường được anh ah.

    Vấn đề này mình đã test trên 2010 và 2013 thì đúng là không thể tham chiếu vùng vượt qua con số 65.536 dòng. Trên 2007 mình trước giờ không xài nên không test được.

    Thử sửa như vậy xem :

    Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:myFoldermyExcel2007file.xlsm;
    Extended Properties="Excel 12.0 Macro;HDR=YES";

    Nếu sửa lại giống hệt thì code không chạy được cũng không có thông báo lỗi . Còn nếu sửa nội dung của bạn [URL='https://www.giaiphapexcel.com/forum/member.php?u=448918'%5Ddhn46 thành nội dung của ban[URL='https://www.giaiphapexcel.com/forum/member.php?728818-hungpecc1'%5D hungpecc1 tức là phần màu đỏ phải đặt trong dấu nháy kép màu xanh (thế này : " "Excel 12.0 Macro;HDR=YES" " ) thì cũng hiện hộp thoại báo lỗi như thế . Mình đang dùng MSE 2010

    Chuyển dữ liệu sang lưu trữ tại 1 bảng của Access, ưu điểm là dể truy vấn, dung lượng lưu trữ nhiều…

    Chưa hiểu ý của Bạn . Chỉ chuyển dữ liệu (cụ thể là sheet "CSDL") hay là chuyển cả ý tưởng (thay vì dùng Excel để quản lý thì ta nên dùng Access) . Không biết ý bạn là thế nào , có thể nói rõ hơn không?

    Chuyển sheet CSDL vào 1 bảng của Access, sau đó cần cái gì thì ở Excel mình kết nối với bảng đó là được.

  2. hands says:

    Thử viết thành 1 hàm dạng tổng quát xem:

    Function GetData(ByVal FileName As String, ByVal SheetName As String, ByVal RangeAddress As String, _
                ByVal HasTitle As Boolean, ByVal UseTitle As Boolean)
    
    Dim rsCon As Object, rsData As Object, cat As Object, tbl As Object
      Dim tmpArr, arr()
      Dim szConnect As String, szSQL As String, tmp As String
      Dim lCount As Long, lR As Long, lC As Long, lVer As Long
      lVer = Val(Application.Version)
      Set rsCon = CreateObject("ADODB.Connection")
      Set rsData = CreateObject("ADODB.Recordset")
      Set cat = CreateObject("ADOX.Catalog")
    
    If lVer < 12 Then
        szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FileName & ";" & _
                    "Extended Properties=""Excel 8.0;HDR=" & IIf(HasTitle, "Yes", "No") & """;"
      Else
        szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & FileName & ";" & _
                    "Extended Properties=""Excel 12.0;HDR=" & IIf(HasTitle, "Yes", "No") & """;"
      End If
      If SheetName = "" Then
        Dim Dbs  As Object, db As Object
        Set Dbs = CreateObject("DAO.DBEngine." & IIf(lVer < 12, "36", "120"))
        Set db = Dbs.OpenDatabase(FileName, False, False, "Excel 8.0;")
        tmp = db.TableDefs(0).Name
        tmp = Replace(tmp, " ", "?")
        tmp = Replace(tmp, "'", " ")
        tmp = WorksheetFunction.Trim(tmp)
        tmp = Replace(tmp, " ", "'")
        tmp = Replace(tmp, "?", " ")
        SheetName = tmp
        db.Close
        Set Dbs = Nothing: Set db = Nothing
      End If
      If Right(SheetName, 1) <> "$" Then SheetName = SheetName & "$"
      rsCon.Open szConnect
      cat.ActiveConnection = rsCon
    
    szSQL = "SELECT * FROM [" & SheetName & RangeAddress & "];"
      rsData.Open szSQL, rsCon, 0, 1, 1
      tmpArr = rsData.GetRows
      ReDim arr(UBound(tmpArr, 2) - UseTitle, UBound(tmpArr, 1) + 1)
      If UseTitle Then
        For lC = LBound(tmpArr, 1) To UBound(tmpArr, 1)
          arr(0, lC) = rsData.Fields(lC).Name
        Next
      End If
      For lR = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        For lC = LBound(tmpArr, 1) To UBound(tmpArr, 1)
          arr(lR - UseTitle, lC) = tmpArr(lC, lR)
        Next
      Next
      rsData.Close: Set rsData = Nothing
      rsCon.Close: Set rsCon = Nothing
      GetData = arr
    End Function

    ———————
    Code ở trên ta chẳng cần quan tâm, chỉ cần biết áp dụng là được (truyền tham số vào)
    Cú pháp

    GetData(Đuòng dẫn đến file nguồn, Tên Sheet, Vùng dữ liệu, Dữ liệu có tiêu đề không?, Có muốn lấy tiêu đề không?)

    Ví dụ:

    Sub Main()
      Dim arr
      On Error Resume Next
      arr = GetData(ThisWorkbook.Path & "Nguon.xlsm", "CSDL", "AB35:IJ100000", False, False)
      If IsArray(arr) Then Range("AB35").Resize(UBound(arr, 1) + 1, UBound(arr, 2) + 1).Value = arr
    End Sub
    Sub Main()   Dim arr   On Error Resume Next   arr = GetData(ThisWorkbook.Path & "Nguon.xlsm", "CSDL", "AB35:IJ100000", False, False)   If IsArray(arr) Then Range("AB35").Resize(UBound(arr, 1) + 1, UBound(arr, 2) + 1).Value = arr End Sub

    Thủ tục này đặt ở file nào vậy Bạn (Nguon.xlsm hay Dich.xlsm) ? Không thấy đề cập đến file: Dich.xlsm

    Toàn bộ code đặt trong Module của file Dich.xlsm

    Vấn đề của mình : Không mở file: Dich.xlsm . Mọi công việc làm trên file : Nguon.xlsm sau đó chạy code để copy dữ liêu sang file Dich.xlsm mà không cần mở file : Dich.xlsm . Bạn có cách nào sửa code lại không ? xin cám ơn !

  3. hands says:

    Code của Bác Ndu mình chạy trên Portable Offic 2007 thấy "ngọt" quá.
    Bây giờ lại thêm 1 yêu cầu: Không mở file lên mà vẫn ghi dữ liệu vào.
    Mình chỉ theo dõi chứ cái zụ này không rành.

    Vậy bài toán của bạn là: GHI DỮ LIỆU VÀO FILE ĐANG ĐÓNG (chứ hổng phải lấy dữ liệu từ file đang đóng)
    Nói chung là: TÔI KHÔNG BIẾT (Dù biết có loại code dạng này nhưng chả có nhu cầu gì nên cũng cóc thèm nghiên cứu)

    Giả sử em có dữ liệu cột A1:A100000
    Gõ hàm : Arr = getData(thisworkbook.fullname,"sheet1","A1:A100000",false,false)
    Em test thấy hàm getData của anh cũng chỉ lấy được dữ liệu từ 1: 65536 dòng thôi, nếu vượt hơn số này thì code sẽ báo lỗi như anh HLMT đã đề cập! <— cũng không rõ tại sao !

    Định sửa đoạn này:

    szSQL = "SELECT * FROM [" & SheetName & RangeAddress & "];"

    Thành:

    szSQL = "SELECT * FROM [" & SheetName & "][" & RangeAddress & "];"

    Nhưng thấy cũng chưa ổn (hết lỗi nhưng kết quả không chính xác)
    Để suy nghĩ thêm xem

    Em nghĩ được giải pháp này ! anh xem có ok không:
    Ta sẽ dùng câu lệnh :
    SELECT TOP
    như vậy em sẽ viết là :

    Lrows = Range(RangeAddress).Rows.Count
    –> SzSQL = "SELECT TOP " & Lrows & " * FROM [" & SheetName & "$];"

    Em test thử file của em thì ok, a test thử xem như thế nào !

    Vậy để xác định cái Lrows đó thì phải làm sao? Mở file rồi xác định?

    *Lrows chỉ là 1 số thôi mà anh , giả sử "A1:A100000" thì ta xác định được ngay Lrows = 100000 mà –> Arr = .Getrows(Lrows,0) hoặc dùng SELECT TOP Lrows
    * Cái khoai ở đây là : giải sử DataRange = "An:Am" ( với n <> 1) thì có lẽ lúc này ta phải dùng vòng lặp đưa toàn bộ dữ liệu vào mảng như kiểu :

    For i = n to m
    rst.AbsolutePositon = i
    < xử lý đưa vào mảng >
    next

    * Còn 1 cái khoai nữa : giả sử DataRange = "Xn:Ym" ( với X <> A) thì lúc này nếu ta viết [sheet1$X:Y] thì cũng chỉ lấy được 65536 dòng thôi —> lúc này hổng có lẽ lại phải xác định X,Y là Fx ?,Fy? để đưa vào câu lệnh SELECT
    ===> Từ các * trên –> hàm getdata của anh Ndu là ok rồi người dùng nên cân nhắc đọc kỹ hướng dẫn sử dụng trước khi dùng !$@!!,( ^^ đến Advanced Filter cũng chỉ được đến 10^4dòng thôi mà )

    =================================================

    Trước tiên , xin cám ơn Bạn đã quan tâm và giúp đỡ . Nếu như đề tài mình ghi không rõ ràng mà làm Bạn tốn nhiều thời gian quý báo vào đó thì mình thật sự xin lỗi , do cách diễn giải vấn đề mỗi người mỗi khác mong Bạn thông cảm đừng để trong lòng

    Nhân đây mình cũng xin nói thêm : việc "GHI DỮ LIỆU VÀO FILE ĐANG ĐÓNG" cũng có giá trị thực tiễn của nó . Thực tế file: Nguon.xlsm là 1 file gốc giúp ta quản lý 1 CSDL các mặt hàng (gồm các tiêu chí : Mã – Tên hàng – Giá – và các thông tin khác) với các chức năng : Tạo – Xoá – Cập nhật – Lưu – Các chức năng khác

    Khi file : Nguon.xlsm thay đổi thì code sẽ thực hiện 2 tác vụ chính
    Thứ 1 : Copy dữ liệu từ file: Nguon.xlsm sang file: Dich.xlsm để cập nhật
    Thứ 2 : Chạy code (trên file: Dich.xlsm) để Save as file này từ Dich.xlsm thành file : USM.xlam (Add in)
    Car 2 tác vụ đó nhằm mục đích cập nhật sự thay đổi file : USM.xlam theo sự thay đổi của file : Nguon.xlsm

    Từ file: USM.xlam ta có thể xây dựng các ứng dụng nhỏ (nhằm mục đích chia nhỏ file: Nguon.xlsm và tăng tốc mở file để chạy ứng dụng) từ việc khác thác Mã trong file Add in . Ví dụ : Bán hàng , Mua hàng, Thống kê hàng , Tìm kiếm thông tin hàng hoá , v.v. .

    Nhưng do có nhiều vấn đề liên quan và không tiện hỏi cùng lúc , nên mình mới chia nhỏ vấn đề ra cho đơn giản thế mà lại gây hiểu lầm . Mình xin các bạn thông cảm , đừng để trong lòng , xin mọi người hãy quan tâm giúp đỡ . Xin cám ơn !+-+-+-++-+-+-++-+-+-+

    Vâng! Thì tôi đâu có trách bạn gì đâu (bạn hiểu lầm thôi)
    Bạn cũng biết rằng mấy cái vụ nghiên cứu lập trình này nó phải có "cảm hứng"… Chỉ vì tôi hổng có nhu cầu thực tế nên cũng hổng có cảm hứng để nghiên cứu —-> Tức là LỖI TỪ TÔI mà thôi
    Ẹc… Ẹc…
    Trong khi chờ đợi, bạn có thể tạm dùng giải pháp: Mở file, copy dữ liệu, paste vào rồi đóng file và lưu
    Tôi nghĩ thế cũng đâu có vấn đề gì

    Đọc các bài viết thấy trên , dường như MSE KHÔNG CÓ KHẢ NĂNG lọc (advanced Filter) hoặc sao chép (copy) với số lượng dòng (record) lớn đến 1048576 dòng .

    Như bạn hungpecc1 nói:

    đến Advanced Filter cũng chỉ được đến 10^3 dòng thôi mà

    Còn bạn ndu96081631 nói :

    bạn có thể tạm dùng giải pháp: Mở file, copy dữ liệu, paste vào rồi đóng file và lưu

    Cái này MSE nó báo lỗi , thậm chí mình cũng dùng thử cách của bạn hôm rồi : Copy vào mảng, dán giá trị từ mảng vào đích (với số dòng 1048576) cũng bị lỗi

    Có phải mình lựa chọn MSE để quản lý CSDL là KHÔNG HỢP LÝ không ? Không biết các Bạn có ý kiến gì ? Mình nghĩ 1 CSDL cần có thể LỌC và SAO CHÉP được thì mới khai thác được ,không biết các Bạn có để đề xuất cho mình được giải pháp nào không ? Xin cám ơn

    Như bài [URL='https://www.giaiphapexcel.com/forum/showthread.php?82596-S%E1%BB%AD-d%E1%BB%A5ng-ADO-%C4%91%E1%BB%83-copy-d%E1%BB%AF-li%E1%BB%87u-t%E1%BB%AB-file-n%C3%A0y-sang-file-kh%C3%A1c&p=513073#post513073'%5D21 tôi đã đề cập, để lưu trữ dữ liệu với dung lượng lớn thì phải chọn cái khác chứ không phải excel, mà đó là Access hoặc SQL Server.

    Mình nói nhầm bạn nhé Advanced Fillter khoảng 10^4 dòng bạn nhé, với số lượng lớn thì có thể dùng Remove Duplictae
    bạn nên nhớ rằng Excel không phải là CSDL , excel chỉ là bảng tính –> Tùy trường hợp mà ta có thể áp dụng coi Excel là 1 CSDL,
    Còn nếu bạn có 1 CSDL hoàn chỉnh thì như anh HLMT đã nói –> chuyển qua Accsess, nếu nhiều dữ liệu thì chia làm nhiều bảng , nhiều file trong access !

    ======================================

    Chức năng Filter của MSE có thể xử lý được đến cả dòng thứ 1048576 , vậy tai sao copy với số lượng dòng (record) 1048576 thì không thể được vậy anh Hai lúa miền tây ?

    Với tôi dữ liệu lên đến 10.000 dòng là đã quá nhiều, tôi chưa từng có dữ liệu hết dòng trên excel 2007 và nếu có chăng đi nữa tôi cũng chọn giải pháp khác vì với số lượng dòng như thế này chắc gì máy cùi bấp như của tôi nó chạy nổi. Với yêu cầu của bạn tôi thật sự bó tay.

    Anh Hai lúa miền tây có thể nói sơ về ưu điểm và khuyết điểm giữa Access và SQL Server cho mình mở mang không ?

    1.) Về dung lượng:
    – SQL Server bạn có thể tham khảo [URL='https://msdn.microsoft.com/en-us/library/ms143432.aspx'%5DTại đây
    – Access chỉ được 2 gigabyte
    2.) Về bảo mật:
    – SQL Server có chính sách bảo mật hơn là Access.
    3.) Kết nối dữ liệu từ xa qua Internet:
    – SQL Server là ưu thế.
    – Access: Có thể được nhưng phức tạp (Xin lỗi mình chưa thử dạng này)

    Trên đây là những điểm nhận xét riêng của mình, dĩ nhiên sẽ còn có những điểm đáng lưu ý khác.

    Trong khi chờ đợi, bạn có thể tạm dùng giải pháp: Mở file, copy dữ liệu, paste vào rồi đóng file và lưu
    Tôi nghĩ thế cũng đâu có vấn đề gì

    Bạn có thể giúp mình xây đựng 1 hàm truyền tham số:
    1. File: Nguon.xlsm đang mở, file: Dich.xlsm đang đóng
    2. Hàm có tác dụng
    – Copy 1 vùng trong Nguon.xlsm tại sheet: "CSDL"
    – Dán lấy giá trị vào Dich.xlsm tại sheet : "SP"
    Mình sẽ kết hợp hàm này với vòng lặp FOR (xác định số lần copy dựa trên vị trí dòng cuối cùng của cột "AB" và số dòng tối đa mà hàm có thể sao chép đc = việc xác định này ta dùng hàm INT , IFF và MOD) như thế sẽ khắc phục được lỗi copy với số luợng dòng (record) quá lớn mà MSE ko thể làm đc . Bạn thấy sao !

    ======================================

    Anh ơi, có cách nào để giữ nguyên định dạng dữ liệu ở các cột như định dạng ở file gốc không anh?

    Để giữ định dạng thì chỉ có cách mở file, copy và paste thôi
    Hoặc cũng có cách là sau khi lấy được dữ liệu, ta tự mình định dạng lại (bằng tay hoặc bằng code)

    Vâng, nhưng khi định dạng bằng tay cột ngày tháng năm không được anh. Em có gửi file vào mail cho anh rồi, anh xem giúp em cột ngày đến hạn.
    Có trường hợp khi file nguồn mở thì không gặp lỗi trên!
    Với trường hợp dữ liệu lớn thì khi mở file copy và paste thì rất chậm…
    Cảm ơn anh đã trả lời!

  4. hands says:

    Bạn sử dụng Code sau

    Option Explicit
    Sub Update()
        On Error GoTo Handle
        Dim cnn As Object, lsSQL As String, lrs As Object, FileFullName As String
        Set cnn = CreateObject("ADODB.Connection")
        Set lrs = CreateObject("ADODB.Recordset")
        FileFullName = Application.ThisWorkbook.Path & "Nguon.xlsm"
        With cnn
            .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" _
                    & "Data Source=" & FileFullName _
                    & ";Extended Properties=""Excel 12.0;HDR=No"";"
            .Open
        End With
        lsSQL = "Select * From [CSDL$AB35:IJ100000] Where f1 Is Not Null"
        lrs.Open lsSQL, cnn, 3, 1
        If Sheets("SP").[AB35] = "" Then
            Sheets("SP").Range("AB35").CopyFromRecordset lrs
        Else
            Sheets("SP").Range("AB35").End(xlDown).Offset(1, 0).CopyFromRecordset lrs
        End If
        MsgBox "Da Update CSDL", vbInformation
        Set lrs = Nothing
        cnn.Close: Set cnn = Nothing
        Exit Sub
    Handle:
        MsgBox Err.Description
    End Sub

    Tôi muốn đọc dữ liệu từ nhiều file, mỗi file có số sheet khác nhau nhưng cấu trúc đều như nhau và đều bắt đầu từ ô A5.
    Danh sách các file nằm trong A2 đến A10

    Liệu có thể dùng (gặp mã lệnh không chính xác thì tôi mô tả bằng lời) và đặt vô vị trí (1)

    For i = 2 to 10
    FileFullName= cells(i,1)
    for J = 1 to sheets.count

    Các lệnh để kết nối dữ liệu, trong đó cần hiệu chỉnh tên sheet của dòng lệnh (2) (chỗ có CSDL )

    Xin hỏi như thế có được không. Nếu được thì 3 câu lệnh trên đặt ở (1) có được không hay chỗ khác. Phải đặt các câu lệnh

    Next J
    Next I

    ở chỗ nào.

    Xin cảm ơn

    1./ Kết nối với file nguồn.
    2./ Lấy danh sách sheet của file nguồn đó.
    3./ Duyệt qua từng sheet. Lưu ý nên loại bỏ những bảng mà không phải là tên sheet (Name, filter…)
    4./ Đọc dữ liệu của từng sheet.

    Cảm ơn anh lúa.
    Đang dịp bận quá, bữa sau gửi file đính kèm (tối thiểu 3 file, 2 file dữ liệu gốc, 1 file đích) nhờ anh và diễn đàn

    =========================

    Cho em hỏi ADO có xử lý được trường hợp thế này ko?
    em có 2 file DM và Goc. File DM là file nguồn, file Goc là file cần lấy dữ liệu từ file nguồn ( dữ liệu file DM có thể 2 hoặc 3 sheet). Ở sheet1 file gốc có 2 button, khi em nhấn button DM1776 thì dữ liệu ở sheet DM1776 của file Góc sẽ được copy và pas từ sheet DM1776 của file DM và tương tự nếu nhấn vào sheet DMXL file Goc thì dữ liệu cũng được copy và past từ sheet DMLD của file DM qua file Goc.

    Trường hợp của bạ hoàn toàn có thể làm được, nhưng CSDL của bạn không thuộc dạng chuẩn nên khuyến cáo không nên dùng ADO. Bạn có thể thử với code sau để tham khảo

    Option Explicit
    Sub Update()
        On Error GoTo Handle
        Dim cnn As Object, lsSQL As String, lrs As Object, FileFullName As String
        Set cnn = CreateObject("ADODB.Connection")
        Set lrs = CreateObject("ADODB.Recordset")
        FileFullName = Application.ThisWorkbook.Path & "[B]DM.xls[/B]"
        With cnn
            .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" _
                                & "Data Source=" & FileFullName _
                                & ";Extended Properties=""Excel 12.0;HDR=No"";"
            .Open
        End With
        lsSQL = "Select * From [[B]DMLD$A5:Q6536[/B]]"
        lrs.Open lsSQL, cnn, 3, 1
       [B] Sheet3.Range("A5")[/B].CopyFromRecordset lrs
        Set lrs = Nothing
        cnn.Close: Set cnn = Nothing
        Exit Sub
    Handle:
        MsgBox Err.Description
    End Sub

    Có cái gì đó ko ổn. Em chạy thử code ko có hiện tượng gì ngoài thông báo: " Provider cannot be found. It may not be properly íntalled

    Bạn chắc là dùng Excel 2003. Vậy bạn sửa lại 1 chút

    Option Explicit
    Sub Update()
        On Error GoTo Handle
        Dim cnn As Object, lsSQL As String, lrs As Object, FileFullName As String
        Set cnn = CreateObject("ADODB.Connection")
        Set lrs = CreateObject("ADODB.Recordset")
        FileFullName = Application.ThisWorkbook.Path & "DM.xls"
        With cnn
            If Val(Application.Version) < 12 Then
                .ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FileFullName & ";Extended Properties=""Excel 8.0;HDR=No"";"
            Else
                .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & FileFullName & ";Extended Properties=""Excel 12.0;HDR=No"";"
            End If
            .Open
        End With
        lsSQL = "Select * From [DMLD$A5:Q6536]"
        lrs.Open lsSQL, cnn, 3, 1
        Sheet3.Range("A5").CopyFromRecordset lrs
        Set lrs = Nothing
        cnn.Close: Set cnn = Nothing
        Exit Sub
    Handle:
        MsgBox Err.Description
    End Sub

    Update hơi lâu xíu nhưng thôi tạm ổn rồi. TK anh nhiều

  5. hands says:

    Thử viết thành 1 hàm dạng tổng quát xem:

    Function GetData(ByVal FileName As String, ByVal SheetName As String, ByVal RangeAddress As String, _
                ByVal HasTitle As Boolean, ByVal UseTitle As Boolean)
    
    Dim rsCon As Object, rsData As Object, cat As Object, tbl As Object
      Dim tmpArr, arr()
      Dim szConnect As String, szSQL As String, tmp As String
      Dim lCount As Long, lR As Long, lC As Long, lVer As Long
      lVer = Val(Application.Version)
      Set rsCon = CreateObject("ADODB.Connection")
      Set rsData = CreateObject("ADODB.Recordset")
      Set cat = CreateObject("ADOX.Catalog")
    
    If lVer < 12 Then
        szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FileName & ";" & _
                    "Extended Properties=""Excel 8.0;HDR=" & IIf(HasTitle, "Yes", "No") & """;"
      Else
        szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & FileName & ";" & _
                    "Extended Properties=""Excel 12.0;HDR=" & IIf(HasTitle, "Yes", "No") & """;"
      End If
      If SheetName = "" Then
        Dim Dbs  As Object, db As Object
        Set Dbs = CreateObject("DAO.DBEngine." & IIf(lVer < 12, "36", "120"))
        Set db = Dbs.OpenDatabase(FileName, False, False, "Excel 8.0;")
        tmp = db.TableDefs(0).Name
        tmp = Replace(tmp, " ", "?")
        tmp = Replace(tmp, "'", " ")
        tmp = WorksheetFunction.Trim(tmp)
        tmp = Replace(tmp, " ", "'")
        tmp = Replace(tmp, "?", " ")
        SheetName = tmp
        db.Close
        Set Dbs = Nothing: Set db = Nothing
      End If
      If Right(SheetName, 1) <> "$" Then SheetName = SheetName & "$"
      rsCon.Open szConnect
      cat.ActiveConnection = rsCon
    
    szSQL = "SELECT * FROM [" & SheetName & RangeAddress & "];"
      rsData.Open szSQL, rsCon, 0, 1, 1
      tmpArr = rsData.GetRows
      ReDim arr(UBound(tmpArr, 2) - UseTitle, UBound(tmpArr, 1) + 1)
      If UseTitle Then
        For lC = LBound(tmpArr, 1) To UBound(tmpArr, 1)
          arr(0, lC) = rsData.Fields(lC).Name
        Next
      End If
      For lR = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        For lC = LBound(tmpArr, 1) To UBound(tmpArr, 1)
          arr(lR - UseTitle, lC) = tmpArr(lC, lR)
        Next
      Next
      rsData.Close: Set rsData = Nothing
      rsCon.Close: Set rsCon = Nothing
      GetData = arr
    End Function

    ———————
    Code ở trên ta chẳng cần quan tâm, chỉ cần biết áp dụng là được (truyền tham số vào)
    Cú pháp

    GetData(Đuòng dẫn đến file nguồn, Tên Sheet, Vùng dữ liệu, Dữ liệu có tiêu đề không?, Có muốn lấy tiêu đề không?)

    Ví dụ:

    Sub Main()
      Dim arr
      On Error Resume Next
      arr = GetData(ThisWorkbook.Path & "Nguon.xlsm", "CSDL", "AB35:IJ100000", False, False)
      If IsArray(arr) Then Range("AB35").Resize(UBound(arr, 1) + 1, UBound(arr, 2) + 1).Value = arr
    End Sub

    Các anh ơi cho em hỏi, em chỉ muốn lấy dòng cuối cùng trong Range thì sửa thế nào ạ

    Hàm GetData trả về một mảng dữ liệu 2 chiều (dòng và cột). Muốn lấy dòng cuối cùng thì dùng UBound để xác định chỉ số dòng cuối cùng rồi lấy nó ra.

    Không nên sửa cái gì cả vì nếu bạn có khả năng sửa thì đã không hỏi.

    thắc mắc: ADO dùng để lấy dữ liệu hàng loạt. Chỉ lấy dòng cuối thì dùng nó làm gì?

    Em cần lấy một số thông tin rời rạc ở dòng cuối cùng của 1 file tổng đưa vào file chi tiết mà không biết cách lấy thế nào cả ạ

    Bạn lập một tiêu đề như phần tô đậm ở trên. Và mở một câu hỏi khác ở mục "Lập trình với Excel" này. Sẽ có người giúp bạn. Nếu có file mẫu đăng lên thì sẽ nhận được câu trả lời sớm và chính xác hơn.

    Thớt này bàn về ADO. Công cụ ActiveX chỉ giành cho những người đã có kinh nghiệm ít nhiều về VBA.

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