VBA-Cách gộp nhiều file excel vào chung 1 sheet excel duy nhất.

Liên hệ QC

Tiểu Mộc Mộc

Thành viên mới
Tham gia
20/2/19
Bài viết
14
Được thích
0
Anh/chị giúp em với ạ:

Em có 1 đề bài "Gộp nhiều sheet tách biệt vào chung 1 sheet duy nhất", đối với các file có nhiều sheetcó số dòng khác nhau ạ.

Em có 3 file dữ liệu: AB,ABB và ABBB, và em muốn gộp dữ liệu của sheet name "Hoa" của 3 file đó vào 1 sheet "Master" của file Test.

Em gửi anh/chị file đính kèm, anh/chị tiền bối giúp em với ạ, vì hàng tháng em đều phải làm báo cáo với hơn 100 file excel, và mỗi file lại chứa 5 sheet các nhãn hàng khác nhau=> Hàng tháng cứ phải làm báo cáo tất cả các khu vực cho từng nhãn hàng, ngồi làm thủ công mất rất nhiều thời gian ạ :(

Em cảm ơn anh/chị rất nhiều.
 

File đính kèm

  • AB.xlsx
    10.4 KB · Đọc: 57
  • ABB.xlsx
    10.5 KB · Đọc: 47
  • ABBB.xlsx
    11 KB · Đọc: 40
  • Test.xlsm
    11.3 KB · Đọc: 46
Anh/chị giúp em với ạ:

Em có 1 đề bài "Gộp nhiều sheet tách biệt vào chung 1 sheet duy nhất", đối với các file có nhiều sheetcó số dòng khác nhau ạ.

Em có 3 file dữ liệu: AB,ABB và ABBB, và em muốn gộp dữ liệu của sheet name "Hoa" của 3 file đó vào 1 sheet "Master" của file Test.

Em gửi anh/chị file đính kèm, anh/chị tiền bối giúp em với ạ, vì hàng tháng em đều phải làm báo cáo với hơn 100 file excel, và mỗi file lại chứa 5 sheet các nhãn hàng khác nhau=> Hàng tháng cứ phải làm báo cáo tất cả các khu vực cho từng nhãn hàng, ngồi làm thủ công mất rất nhiều thời gian ạ :(

Em cảm ơn anh/chị rất nhiều.

Bạn copy tất cả code dưới vào 1 module và chạy thử xem ạ:
Mã:
Option Explicit
'https://danwagner.co/how-to-combine-multiple-excel-workbooks-into-one-worksheet-with-vba/
Public Sub CombineManyWorkbooksIntoOneWorksheet()
   
    Dim strDirContainingFiles As String, strFile As String, _
        strFilePath As String
    Dim wbkDst As Workbook, wbkSrc As Workbook
    Dim wksDst As Worksheet, wksSrc As Worksheet
    Dim lngIdx As Long, lngSrcLastRow As Long, _
        lngSrcLastCol As Long, lngDstLastRow As Long, _
        lngDstLastCol As Long, lngDstFirstFileRow As Long
    Dim rngSrc As Range, rngDst As Range, rngFile As Range
    Dim colFileNames As Collection
    Set colFileNames = New Collection
   
    'Set references up-front
    strDirContainingFiles = "C:\Users\OanhTho\Desktop\New folder (3)" '<~ your folder
    Rem Set wbkDst = Workbooks.Add '<~ Dst is short for destination
    Set wksDst = ThisWorkbook.Worksheets("Master")
   
    'Store all of the file names in a collection
    strFile = Dir(strDirContainingFiles & "\*.xlsx")
    Do While Len(strFile) > 0
        colFileNames.Add Item:=strFile
        strFile = Dir
    Loop
   
    ''CHECKPOINT: make sure colFileNames has the file names
    'Dim varDebug As Variant
    'For Each varDebug In colFileNames
    '    Debug.Print varDebug
    'Next varDebug
   
    'Now we can start looping through the "source" files
    'and copy their data to our destination sheet
    For lngIdx = 1 To colFileNames.Count
       
        'Assign the file path
        strFilePath = strDirContainingFiles & "\" & colFileNames(lngIdx)
       
        'Open the workbook and store a reference to the data sheet
        Set wbkSrc = Workbooks.Open(strFilePath)
        Set wksSrc = wbkSrc.Worksheets("Hoa") '<~ change based on your Sheet name
       
        'Identify the last row and last column, then
        'use that info to identify the full data range
        lngSrcLastRow = LastOccupiedRowNum(wksSrc)
        lngSrcLastCol = LastOccupiedColNum(wksSrc)
        With wksSrc
            Set rngSrc = .Range(.Cells(1, 1), .Cells(lngSrcLastRow, _
                                                     lngSrcLastCol))
        End With
       
        ''CHECKPOINT: make sure we have the full source data range
        'wksSrc.Range("A1").Select
        'rngSrc.Select
       
        'If this is the first (1st) loop, we want to keep
        'the header row from the source data, but if not then
        'we want to remove it
        If lngIdx <> 1 Then
            Set rngSrc = rngSrc.Offset(1, 0).Resize(rngSrc.Rows.Count - 1)
        End If
       
        ''CHECKPOINT: make sure that we remove the header row
        ''from the source range on every loop that is not
        ''the first one
        'wksSrc.Range("A1").Select
        'rngSrc.Select
       
        'Copy the source data to the destination sheet, aiming
        'for cell A1 on the first loop then one past the
        'last-occupied row in column A on each following loop
        If lngIdx = 1 Then
            lngDstLastRow = 1
            Set rngDst = wksDst.Cells(1, 1)
        Else
            lngDstLastRow = LastOccupiedRowNum(wksDst)
            Set rngDst = wksDst.Cells(lngDstLastRow + 1, 1)
        End If
        rngSrc.Copy Destination:=rngDst '<~ this is the copy / paste
       
        'Almost done! We want to add the source file info
        'for each of the data blocks to our destination
       
        'On the first loop, we need to add a "Source Filename" column
        If lngIdx = 1 Then
            lngDstLastCol = LastOccupiedColNum(wksDst)
            wksDst.Cells(1, lngDstLastCol + 1) = "Source Filename"
        End If
       
        'Identify the range that we need to write the source file
        'info to, then write the info
        With wksDst
       
            'The first row we need to write the file info to
            'is the same row where we did our initial paste to
            'the destination file
            lngDstFirstFileRow = lngDstLastRow + 1
           
            'Then, we need to find the NEW last row on the destination
            'sheet, which will be further down (since we pasted more
            'data in)
            lngDstLastRow = LastOccupiedRowNum(wksDst)
            lngDstLastCol = LastOccupiedColNum(wksDst)
           
            'With the info from above, we can create the range
            Set rngFile = .Range(.Cells(lngDstFirstFileRow, lngDstLastCol), _
                                 .Cells(lngDstLastRow, lngDstLastCol))
                               
            ''CHECKPOINT: make sure we have correctly identified
            ''the range where our file names will go
            'wksDst.Range("A1").Select
            'rngFile.Select
                               
            'Now that we have that range identified,
            'we write the file name
            rngFile.Value = wbkSrc.Name
           
        End With
       
        'Close the source workbook and repeat
        wbkSrc.Close SaveChanges:=False
       
    Next lngIdx
   
    'Let the user know that the combination is done!
    MsgBox "Data combined!"
   
End Sub

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT       : Sheet, the worksheet we'll search to find the last row
'OUTPUT      : Long, the last occupied row
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedRowNum(Sheet As Worksheet) As Long
    Dim lng As Long
    If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
        With Sheet
            lng = .Cells.Find(What:="*", _
                              After:=.Range("A1"), _
                              Lookat:=xlPart, _
                              LookIn:=xlFormulas, _
                              SearchOrder:=xlByRows, _
                              SearchDirection:=xlPrevious, _
                              MatchCase:=False).Row
        End With
    Else
        lng = 1
    End If
    LastOccupiedRowNum = lng
End Function

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT       : Sheet, the worksheet we'll search to find the last column
'OUTPUT      : Long, the last occupied column
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedColNum(Sheet As Worksheet) As Long
    Dim lng As Long
    If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
        With Sheet
            lng = .Cells.Find(What:="*", _
                              After:=.Range("A1"), _
                              Lookat:=xlPart, _
                              LookIn:=xlFormulas, _
                              SearchOrder:=xlByColumns, _
                              SearchDirection:=xlPrevious, _
                              MatchCase:=False).Column
        End With
    Else
        lng = 1
    End If
    LastOccupiedColNum = lng
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn copy tất cả code dưới vào 1 module và chạy thử xem ạ:
Mã:
Option Explicit
'https://danwagner.co/how-to-combine-multiple-excel-workbooks-into-one-worksheet-with-vba/
Public Sub CombineManyWorkbooksIntoOneWorksheet()
   
    Dim strDirContainingFiles As String, strFile As String, _
        strFilePath As String
    Dim wbkDst As Workbook, wbkSrc As Workbook
    Dim wksDst As Worksheet, wksSrc As Worksheet
    Dim lngIdx As Long, lngSrcLastRow As Long, _
        lngSrcLastCol As Long, lngDstLastRow As Long, _
        lngDstLastCol As Long, lngDstFirstFileRow As Long
    Dim rngSrc As Range, rngDst As Range, rngFile As Range
    Dim colFileNames As Collection
    Set colFileNames = New Collection
   
    'Set references up-front
    strDirContainingFiles = "C:\Users\CT9\Desktop\New folder (3)" '<~ your folder
    Rem Set wbkDst = Workbooks.Add '<~ Dst is short for destination
    Set wksDst = ThisWorkbook.Worksheets("Master")
   
    'Store all of the file names in a collection
    strFile = Dir(strDirContainingFiles & "\*.xlsx")
    Do While Len(strFile) > 0
        colFileNames.Add Item:=strFile
        strFile = Dir
    Loop
   
    ''CHECKPOINT: make sure colFileNames has the file names
    'Dim varDebug As Variant
    'For Each varDebug In colFileNames
    '    Debug.Print varDebug
    'Next varDebug
   
    'Now we can start looping through the "source" files
    'and copy their data to our destination sheet
    For lngIdx = 1 To colFileNames.Count
       
        'Assign the file path
        strFilePath = strDirContainingFiles & "\" & colFileNames(lngIdx)
       
        'Open the workbook and store a reference to the data sheet
        Set wbkSrc = Workbooks.Open(strFilePath)
        Set wksSrc = wbkSrc.Worksheets("Hoa") '<~ change based on your Sheet name
       
        'Identify the last row and last column, then
        'use that info to identify the full data range
        lngSrcLastRow = LastOccupiedRowNum(wksSrc)
        lngSrcLastCol = LastOccupiedColNum(wksSrc)
        With wksSrc
            Set rngSrc = .Range(.Cells(1, 1), .Cells(lngSrcLastRow, _
                                                     lngSrcLastCol))
        End With
       
        ''CHECKPOINT: make sure we have the full source data range
        'wksSrc.Range("A1").Select
        'rngSrc.Select
       
        'If this is the first (1st) loop, we want to keep
        'the header row from the source data, but if not then
        'we want to remove it
        If lngIdx <> 1 Then
            Set rngSrc = rngSrc.Offset(1, 0).Resize(rngSrc.Rows.Count - 1)
        End If
       
        ''CHECKPOINT: make sure that we remove the header row
        ''from the source range on every loop that is not
        ''the first one
        'wksSrc.Range("A1").Select
        'rngSrc.Select
       
        'Copy the source data to the destination sheet, aiming
        'for cell A1 on the first loop then one past the
        'last-occupied row in column A on each following loop
        If lngIdx = 1 Then
            lngDstLastRow = 1
            Set rngDst = wksDst.Cells(1, 1)
        Else
            lngDstLastRow = LastOccupiedRowNum(wksDst)
            Set rngDst = wksDst.Cells(lngDstLastRow + 1, 1)
        End If
        rngSrc.Copy Destination:=rngDst '<~ this is the copy / paste
       
        'Almost done! We want to add the source file info
        'for each of the data blocks to our destination
       
        'On the first loop, we need to add a "Source Filename" column
        If lngIdx = 1 Then
            lngDstLastCol = LastOccupiedColNum(wksDst)
            wksDst.Cells(1, lngDstLastCol + 1) = "Source Filename"
        End If
       
        'Identify the range that we need to write the source file
        'info to, then write the info
        With wksDst
       
            'The first row we need to write the file info to
            'is the same row where we did our initial paste to
            'the destination file
            lngDstFirstFileRow = lngDstLastRow + 1
           
            'Then, we need to find the NEW last row on the destination
            'sheet, which will be further down (since we pasted more
            'data in)
            lngDstLastRow = LastOccupiedRowNum(wksDst)
            lngDstLastCol = LastOccupiedColNum(wksDst)
           
            'With the info from above, we can create the range
            Set rngFile = .Range(.Cells(lngDstFirstFileRow, lngDstLastCol), _
                                 .Cells(lngDstLastRow, lngDstLastCol))
                               
            ''CHECKPOINT: make sure we have correctly identified
            ''the range where our file names will go
            'wksDst.Range("A1").Select
            'rngFile.Select
                               
            'Now that we have that range identified,
            'we write the file name
            rngFile.Value = wbkSrc.Name
           
        End With
       
        'Close the source workbook and repeat
        wbkSrc.Close SaveChanges:=False
       
    Next lngIdx
   
    'Let the user know that the combination is done!
    MsgBox "Data combined!"
   
End Sub

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT       : Sheet, the worksheet we'll search to find the last row
'OUTPUT      : Long, the last occupied row
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedRowNum(Sheet As Worksheet) As Long
    Dim lng As Long
    If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
        With Sheet
            lng = .Cells.Find(What:="*", _
                              After:=.Range("A1"), _
                              Lookat:=xlPart, _
                              LookIn:=xlFormulas, _
                              SearchOrder:=xlByRows, _
                              SearchDirection:=xlPrevious, _
                              MatchCase:=False).Row
        End With
    Else
        lng = 1
    End If
    LastOccupiedRowNum = lng
End Function

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INPUT       : Sheet, the worksheet we'll search to find the last column
'OUTPUT      : Long, the last occupied column
'SPECIAL CASE: if Sheet is empty, return 1
Public Function LastOccupiedColNum(Sheet As Worksheet) As Long
    Dim lng As Long
    If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
        With Sheet
            lng = .Cells.Find(What:="*", _
                              After:=.Range("A1"), _
                              Lookat:=xlPart, _
                              LookIn:=xlFormulas, _
                              SearchOrder:=xlByColumns, _
                              SearchDirection:=xlPrevious, _
                              MatchCase:=False).Column
        End With
    Else
        lng = 1
    End If
    LastOccupiedColNum = lng
End Function
Em chạy thử, kết quả data trắng ntn ạ.

1550727788411.png
 
Upvote 0

File đính kèm

  • Test.xlsm
    24.9 KB · Đọc: 126
Upvote 0
Em chạy OK rồi chị ạ.

Em cảm ơn chị rất nhiều.

Chị cho em hỏi khi em thay đổi dữ liệu về số lượng dòng, cột, tên sheet,tên file...thì sẽ chỉnh code ở những dòng nào ạ?

Hỏi hiểu không thực tế bằng thử ,Bạn cứ thử thay đổi xem sao ạ :)
 
Upvote 0
Upvote 0
Khi dữ liệu của em muốn lấy từ B12, có phải chỉ cần thay đổi After:=.Range("A1"), _ thành After:=.Range("B12"), _ có phải không ạ?
View attachment 212510
Bạn sửa:
Mã:
With wksSrc
            Set rngSrc = .Range(.Cells(1, 1), .Cells(lngSrcLastRow, _
                                                     lngSrcLastCol))
        End With

Thành:
Mã:
With wksSrc
            Set rngSrc = .Range(.Cells(12, 2), .Cells(lngSrcLastRow, _
                                                     lngSrcLastCol))
        End With
 
Upvote 0
Upvote 0
Không chấp nhận câu nói này, người Bắc và là phụ nữ thì không nói tắc như vậy
"Hỏi hiểu", "thử"
"Hỏi hiểu không thực tế bằng thử"
Sao OT không giúp bạn ấy bằng ADO

Cảm ơn HeSanbi đã góp ý

Mới đầu OT nghĩ bạn ấy hỏi có xác định dòng cuối hay cột cuối trong các file nguồn không nên mới nói bạn ấy thử vì OT biết code bài trên đã có hàm xác định dòng và cột cuối. Nhưng khi bạn ấy nói rõ thì mới biết dữ liệu lấy bắt đầu từ B12 (mà không phải vấn đề xác định dòng cột cuối cùng).

Về việc sử dụng ADO OT không rành, chắc là thế này ạ (code dưới không phải của OT).Nhưng theo kiến thức của OT nếu đã lấy dữ liệu từ dòng 12 thì không nên sử dụng ADO vì ADO căn cứ vào chuẩn dữ liệu của 8 dòng đầu thì phải.. @@!
https://www.giaiphapexcel.com/diend...ảng-trong-vba-array.46834/page-60#post-905772
Mã:
Option Explicit

Sub ReadData()
    Dim cnn As ADODB.Connection, rst As ADODB.Recordset
    Dim sh As Worksheet, SheetName As String, RangeAddress As String
    Dim I As Long, k As Long, CountFiles As Long, J As Long, files As Variant

    SheetName = "Hoa" & "$": RangeAddress = "A1:Z" & 10000
    files = Application.GetOpenFilename(, , , , True)
   
    If VarType(files) = vbBoolean Then Exit Sub
   
    Set sh = Sheets("Master")
    For k = LBound(files) To UBound(files)
        Set cnn = GetConnXLS(files(k))
        If cnn Is Nothing Then Exit Sub
        Set rst = cnn.Execute("SELECT *,""" & files(k) & """ as [From File] FROM [" & SheetName & RangeAddress & "]")
        CountFiles = CountFiles + 1
        If CountFiles = 1 Then
            For J = 0 To rst.Fields.Count - 1
                sh.Cells(1, J + 1).Value = rst.Fields(J).Name
            Next J
        End If
        I = I + sh.Range("A" & 2 + I).CopyFromRecordset(rst)
        rst.Close
        Set rst = Nothing
        cnn.Close
        Set cnn = Nothing
    Next k
   
    MsgBox "Xong"
   
End Sub

Function GetConnXLS(ByVal cFileName As String, _
Optional ByVal InformErrMSG As Boolean = False)

On Error GoTo errHandling:

'Open ADO connection to excel workbook

Dim oConn As Object
Dim Ext As String, ConnStr As String


Set oConn = CreateObject("ADODB.Connection")

ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                "Data Source=" & cFileName & ";" & _
                "Extended Properties=""Excel 12.0;HDR=Yes;"";"

oConn.Open ConnStr
Set GetConnXLS = oConn

errHandling:
    If Err.Number <> 0 Then
        Set oConn = Nothing
        If InformErrMSG Then
            MsgBox "GetConnXLS" & ": " & Err.Number & " " & Err.Description, vbCritical
        End If
    End If
End Function

Nhờ bạn góp ý thêm hoặc nếu có giải pháp nào tối ưu hơn xin hãy chia sẻ.
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn HeSanbi đã góp ý

Mới đầu OT nghĩ bạn ấy hỏi có xác định dòng cuối hay cột cuối trong các file nguồn không nên mới nói bạn ấy thử vì OT biết code bài trên đã có hàm xác định dòng và cột cuối. Nhưng khi bạn ấy nói rõ thì mới biết dữ liệu lấy bắt đầu từ B12 (mà không phải vấn đề xác định dòng cột cuối cùng).

Về việc sử dụng ADO OT không rành, chắc là thế này ạ (code dưới không phải của OT).Nhưng theo kiến thức của OT nếu đã lấy dữ liệu từ dòng 12 thì không nên sử dụng ADO vì ADO căn cứ vào chuẩn dữ liệu của 8 dòng đầu thì phải.. @@!
https://www.giaiphapexcel.com/diendan/threads/các-câu-hỏi-về-mảng-trong-vba-array.46834/page-60#post-905772
Mã:
Option Explicit

Sub ReadData()
    Dim cnn As ADODB.Connection, rst As ADODB.Recordset
    Dim sh As Worksheet, SheetName As String, RangeAddress As String
    Dim I As Long, k As Long, CountFiles As Long, J As Long, files As Variant

    SheetName = "Hoa" & "$": RangeAddress = "A1:Z" & 10000
    files = Application.GetOpenFilename(, , , , True)
 
    If VarType(files) = vbBoolean Then Exit Sub
 
    Set sh = Sheets("Master")
    For k = LBound(files) To UBound(files)
        Set cnn = GetConnXLS(files(k))
        If cnn Is Nothing Then Exit Sub
        Set rst = cnn.Execute("SELECT *,""" & files(k) & """ as [From File] FROM [" & SheetName & RangeAddress & "]")
        CountFiles = CountFiles + 1
        If CountFiles = 1 Then
            For J = 0 To rst.Fields.Count - 1
                sh.Cells(1, J + 1).Value = rst.Fields(J).Name
            Next J
        End If
        I = I + sh.Range("A" & 2 + I).CopyFromRecordset(rst)
        rst.Close
        Set rst = Nothing
        cnn.Close
        Set cnn = Nothing
    Next k
 
    MsgBox "Xong"
 
End Sub

Function GetConnXLS(ByVal cFileName As String, _
Optional ByVal InformErrMSG As Boolean = False)

On Error GoTo errHandling:

'Open ADO connection to excel workbook

Dim oConn As Object
Dim Ext As String, ConnStr As String


Set oConn = CreateObject("ADODB.Connection")

ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                "Data Source=" & cFileName & ";" & _
                "Extended Properties=""Excel 12.0;HDR=Yes;"";"

oConn.Open ConnStr
Set GetConnXLS = oConn

errHandling:
    If Err.Number <> 0 Then
        Set oConn = Nothing
        If InformErrMSG Then
            MsgBox "GetConnXLS" & ": " & Err.Number & " " & Err.Description, vbCritical
        End If
    End If
End Function

Nhờ bạn góp ý thêm hoặc nếu có giải pháp nào tối ưu hơn xin hãy chia sẻ.
ADODB cũng chỉ là sử dụng SQL dành cho Excel, Access
Nếu OT muốn có thể học thêm kiến thức SQL, NO SQL.

Sau khi đọc lại hướng dẫn code của OT thì có vẻ hơi khó cho người được hướng dẫn.
Ví dụ LastRow, LastCol thì OT lại dùng Phương thức Find
LastRow= .UsedRange.Rows.Count
LastCol = .UsedRange.Columns.Count

Nhiều cách:
PHP:
Sub HangCuoi()
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ActiveSheet
  LastRow = sht.Cells.SpecialCells(xlCellTypeLastCell).Row
  LastRow = sht.UsedRange.Rows(sht.UsedRange.Rows.Count).Row
  LastRow = sht.ListObjects("Table1").Range.Rows.Count
  LastRow = sht.Range("MyNamedRange").Rows.Count
  LastRow = sht.Range("A1").CurrentRegion.Rows.Count
End Sub
'Từ đây suy ra cột cuối
 
Lần chỉnh sửa cuối:
Upvote 0
ADODB cũng chỉ là SQL dành cho Excel, Access
Nếu OT muốn có thể học thêm kiến thức SQL, NO SQL.
...
Xui dại con nít. Vậy mà cũng giải thích.
SQL = Structured Query Language . Đó là một ngôn ngữ dùng để truy vấn CSDL Liên Hệ (Relational Database)
ADODB = Active Data Object - Database. Đó là một đối tượng dùng để truy vấn dữ liệu, thường dùng cho CSDL Liên Hệ.
Phân biệt rõ rệt: một đằng là ngôn ngữ, một đằng là gói phần mềm (API, Package, vv...)
Và xác định rõ rệt: ADO không chỉ giành riêng cho Excel, Access.

Quan trọng: vì MS có ra một phần mềm CSDL lấy tên là SQL Server cho nên nhiều người gọi tắt nó là SQL. Và gọi tắt như vậy là sai.
Thực tế, SQL là ngôn ngữ được IBM đẻ ra và về sau được tiêu chuẩn hoá.

Tuy SQL có tiêu chuẩn, nhưng thực tế mỗi loại phần mềm CSDL dùng phiên bản SQL riêng của nó. Access dùng phiên bản Access, SQL Server dùng TSQL, Oracle dùng SQL-Plus,...

Khi dùng ADO để truy vấn CSDL, code phải đưa ra chuỗi kết nối, và trong chuỗi này có nêu ra là dùng cỗ máy của phần mềm nào.

Điển hình là trong VBA, ADO thường được dùng để truy vấn dữ liệu file CSV, Excel, hoặc Access cho nên lúc kết nối, người ta bảo nó dùng cỗ máy Access (Provider=Jet, ACE). Và vì dùng cỗ máy Access cho nên câu lệnh truy vấn được viết theo phiên bản SQL của Access.
Nếu kết nối với SQL Server thì phải dùng cỗ máy của SQL Server, và câu lệnh truy vấn phải viết theo phiên bản T-SQL.

Chú thích:
Một trong những ví dụ sự khác biệt là SQL của Access dùng hàm IIF trong khi T-SQL dùng Case When.
Khi Group, T-SQL theo đúng tiêu chuẩn chung, tức là chỉ cho select những trường đã grouped, những trường khong grouped thì phải qua hàm tổng (aggregate). Phiên bản của MySQL không bắt buộc các trường không grouped phải qua hàm tổng.
 
Upvote 0
Xui dại con nít. Vậy mà cũng giải thích.
SQL = Structured Query Language . Đó là một ngôn ngữ dùng để truy vấn CSDL Liên Hệ (Relational Database)
ADODB = Active Data Object - Database. Đó là một đối tượng dùng để truy vấn dữ liệu, thường dùng cho CSDL Liên Hệ.
Phân biệt rõ rệt: một đằng là ngôn ngữ, một đằng là gói phần mềm (API, Package, vv...)
Và xác định rõ rệt: ADO không chỉ giành riêng cho Excel, Access.

Quan trọng: vì MS có ra một phần mềm CSDL lấy tên là SQL Server cho nên nhiều người gọi tắt nó là SQL. Và gọi tắt như vậy là sai.
Thực tế, SQL là ngôn ngữ được IBM đẻ ra và về sau được tiêu chuẩn hoá.

Tuy SQL có tiêu chuẩn, nhưng thực tế mỗi loại phần mềm CSDL dùng phiên bản SQL riêng của nó. Access dùng phiên bản Access, SQL Server dùng TSQL, Oracle dùng SQL-Plus,...

Khi dùng ADO để truy vấn CSDL, code phải đưa ra chuỗi kết nối, và trong chuỗi này có nêu ra là dùng cỗ máy của phần mềm nào.

Điển hình là trong VBA, ADO thường được dùng để truy vấn dữ liệu file CSV, Excel, hoặc Access cho nên lúc kết nối, người ta bảo nó dùng cỗ máy Access (Provider=Jet, ACE). Và vì dùng cỗ máy Access cho nên câu lệnh truy vấn được viết theo phiên bản SQL của Access.
Nếu kết nối với SQL Server thì phải dùng cỗ máy của SQL Server, và câu lệnh truy vấn phải viết theo phiên bản T-SQL.

Chú thích:
Một trong những ví dụ sự khác biệt là SQL của Access dùng hàm IIF trong khi T-SQL dùng Case When.
Khi Group, T-SQL theo đúng tiêu chuẩn chung, tức là chỉ cho select những trường đã grouped, những trường khong grouped thì phải qua hàm tổng (aggregate). Phiên bản của MySQL không bắt buộc các trường không grouped phải qua hàm tổng.
"Ngày xưa con kiến đi bằng hai chân nay tiến hóa đi 6 chân"
Balablua -> quy về Vũ Trụ
Có khi tôi phải giải thích và nói cho bạn OT kia hiểu cả Lịch sử Microsoft bằng cách gửi OT "đến USA bằng máy bay giấy VN".
Đơn giản bây giờ Google là một "bộ Kinh", Chuyện gì cũng đã có Google, Wikipedia, Balabualua, Túa lua xua...
Tôi cũng không phải "thầy giảng đạo" giảng "trọn bộ Kinh"
Vốn dĩ mỗi từ viết ra nó là một keyword, người vận dụng tốt keyword thì có thêm kiến thức.
 
Lần chỉnh sửa cuối:
Upvote 0
"Ngày xưa con kiến đi bằng hai chân nay tiến hóa đi 6 chân"
Balablua -> quy về Vũ Trụ
Có khi tôi phải giải thích và nói cho bạn OT kia hiểu cả Lịch sử Microsoft bằng cách gửi OT "đến USA bằng máy bay giấy VN".
Đơn giản bây giờ Google là một "bộ Kinh", Chuyện gì cũng đã có Google, Wikipedia, Balabualua, Túa lua xua...
Tôi cũng không phải "thầy giảng đạo" giảng "trọn bộ Kinh"
Vốn dĩ mỗi từ viết ra nó là một keyword, người vận dụng tốt keyword thì có thêm kiến thức.

Gú gồ keyword #IF thì ra được kiến thức Hash Function?
 
Upvote 0
Chào các bạn

Mình có tham khảo code của OT trên đây, yêu cầu của mình đơn giản hơn, nhưng theo chiều ngược lại: Mình muốn lấy dữ liệu trong file excel đang mở để ghi vào môt file excel đích cố định (Là file D:\work\book2.xlsx) và cũng không cần mở file đích này.

Mình sửa lại code như dưới đây, nhưng khi chạy thì nó báo lỗi "Subscript out of range", các bạn sửa giúp mình với (phần Function mình vẫn để nguyên như bài trên)

Mã:
Sub read_data()
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim sh As Worksheet
Dim I As Long, k As Long, CountFiles As Long

RangeAddress = Application.InputBox("Chon vung du lieu co 10 cot (A --> J)", , ActiveCell.CurrentRegion.Address, , , , , 8)
files = "D:\WORKS\book2.xlsx"
Set sh = Sheets("sheet1")

    Set cnn = GetConnXLS(files)
    If cnn Is Nothing Then
        MsgBox "check lai co so du lieu file: " & files
        Exit Sub
    End If
    
    Set rst = cnn.Execute("Select*,"" & files &"" as [from File] From[" & RangeAddress & "]")
    
        For J = 0 To rst.Fields.Count
            sh.Cells(3, J + 1).Value = rst.Fields(J).Name
        Next J
    
    sh.Range("A" & 4).CopyFromRecordset (rst)
    rst.Close
    Set rst = Nothing
    cnn.Close
    Set cnn = Nothing
'Next k
MsgBox "done"
End Sub
 
Upvote 0
E có thắc mắc như bạn đầu tiên hỏi, nhưng mỗi file của e chỉ có 1 sheet, tên file với tên sheet giống nhau, đánh số thứ tự từ 01, 02, 03,.... anh/chị code giúp e với ạ.
 
Upvote 0
Anh/chị giúp em với ạ:

Em có 1 đề bài "Gộp nhiều sheet tách biệt vào chung 1 sheet duy nhất", đối với các file có nhiều sheetcó số dòng khác nhau ạ.

Em có 3 file dữ liệu: AB,ABB và ABBB, và em muốn gộp dữ liệu của sheet name "Hoa" của 3 file đó vào 1 sheet "Master" của file Test.

Em gửi anh/chị file đính kèm, anh/chị tiền bối giúp em với ạ, vì hàng tháng em đều phải làm báo cáo với hơn 100 file excel, và mỗi file lại chứa 5 sheet các nhãn hàng khác nhau=> Hàng tháng cứ phải làm báo cáo tất cả các khu vực cho từng nhãn hàng, ngồi làm thủ công mất rất nhiều thời gian ạ :(

Em cảm ơn anh/chị rất nhiều.
Dùng thử theo link bài này thử xem
 
Upvote 0
E có thắc mắc như bạn đầu tiên hỏi, nhưng mỗi file của e chỉ có 1 sheet, tên file với tên sheet giống nhau, đánh số thứ tự từ 01, 02, 03,.... anh/chị code giúp e với ạ.
Quăng file lên sẽ có người code cho bạn, những bài dạng này trên diễn đàn rất nhiều. code ADO là giải pháp có thể nói đến trong trường hợp này
 
Upvote 0
Web KT
Back
Top Bottom