Hỏi về vấn đề Dồn dữ liệu từ nhiều bảng vào một bảng? (1 người xem)

  • Thread starter Thread starter KUMI
  • Ngày gửi Ngày gửi
Liên hệ QC

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

KUMI

Bụi phấn
Tham gia
17/1/12
Bài viết
564
Được thích
571
Xin Chào Thầy Cô và Anh Chị trong GPE!
Em có một vấn đề cần sự giúp đỡ của GPE. Cụ thể câu hỏi em đã nêu trong file kèm.
Thầy Cô và Anh Chị có cách nào không giúp đỡ Em với ạ.
Xin hỏi thêm bài này của Em có thể dùng công thức được không ạ?
Xin cảm ơn GPE!
 

File đính kèm

Xin Chào Thầy Cô và Anh Chị trong GPE!
Em có một vấn đề cần sự giúp đỡ của GPE. Cụ thể câu hỏi em đã nêu trong file kèm.
Thầy Cô và Anh Chị có cách nào không giúp đỡ Em với ạ.
Xin hỏi thêm bài này của Em có thể dùng công thức được không ạ?
Xin cảm ơn GPE!
Dùng Query như clip sau nhé.

[video=youtube;5wkeCVGUzOg]http://www.youtube.com/watch?v=5wkeCVGUzOg&feature=youtu.be[/video]
 
Upvote 0
Xin Chào Thầy Cô và Anh Chị trong GPE!
Em có một vấn đề cần sự giúp đỡ của GPE. Cụ thể câu hỏi em đã nêu trong file kèm.
Thầy Cô và Anh Chị có cách nào không giúp đỡ Em với ạ.
Xin hỏi thêm bài này của Em có thể dùng công thức được không ạ?
Xin cảm ơn GPE!

Viết hàm dạng tổng quát luôn:
1> Hàm chính:
Mã:
Function Join2DArray(ParamArray arrays())
  Dim arr(), aSub, tmp
  Dim lRs As Long, lCs As Long, lR As Long, lC As Long
  Dim n As Long, m As Long, i As Long, bChk As Boolean
  On Error Resume Next
  For i = 0 To UBound(arrays)
    aSub = arrays(i)
    n = UBound(aSub, 1) - LBound(aSub, 1) + 1
    lRs = lRs + n
    m = UBound(aSub, 2) - LBound(aSub, 2) + 1
    If lCs < m Then lCs = m
  Next
  
  ReDim arr(1 To lCs, 1 To lRs)
  n = 0: m = 0
  For i = 0 To UBound(arrays)
    aSub = arrays(i)
    For lR = LBound(aSub, 1) To UBound(aSub, 1)
      bChk = False
      n = n + 1
      For lC = LBound(aSub, 2) To UBound(aSub, 2)
        tmp = aSub(lR, lC)
        Select Case VarType(tmp)
          Case 0 To 1: arr(lC, n) = vbNullString
          Case 2 To 7: arr(lC, n) = tmp
          Case 8
            If IsNumeric(tmp) Then
              arr(lC, n) = "'" & tmp
            Else
              arr(lC, n) = tmp
            End If
        End Select
        If Len(CStr(tmp)) Then bChk = True
      Next
      If bChk = False Then n = n - 1
    Next
  Next
  If n Then
    ReDim Preserve arr(1 To lCs, 1 To n)
    Join2DArray = Transpose2DArray(arr)
  End If
End Function
Function Transpose2DArray(ByVal arr2D)
  Dim arr(), aTemp
  Dim lR As Long, lC As Long
  On Error Resume Next
  aTemp = arr2D
  ReDim arr(LBound(aTemp, 2) To UBound(aTemp, 2), LBound(aTemp, 1) To UBound(aTemp, 1))
  For lR = LBound(aTemp, 1) To UBound(aTemp, 1)
    For lC = LBound(aTemp, 2) To UBound(aTemp, 2)
      arr(lC, lR) = aTemp(lR, lC)
    Next
  Next
  Transpose2DArray = arr
End Function
2> Áp dụng:
Join2DArray(... Có bao nhiêu bảng dữ liệu thì liệt kê vào đây...)
Ví dụ:
Mã:
Sub Main()
  Dim aRes
  With Sheet1
    aRes = Join2DArray(.Range("E10:G19"), .Range("J10:M19"), .Range("O10:Q19"))
    .Range("E24").Resize(UBound(aRes, 1), UBound(aRes, 2)).Value = aRes
  End With
End Sub
Xong!
Chỉ cần quan tâm việc áp dụng tại Sub Main cho đúng cách, tức là liệt kê các bảng dữ liệu vào (hàm chính viết gì thây kệ nó)
 
Upvote 0
Hihi! Cảm ơn Anh Hai và Thầy nhiều ạ!
Cách của Anh Hai đúng là rất thuận tiện cho người không biết vba như Em nhưng thao tác cũng dài nhỉ mỗi lần cập nhật dữ liệu lại phải làm như vậy ạ!
Còn code của Thầy NDU đúng là em không hiểu gì @@ ,nhưng Thầy bảo rồi cứ Sub Main mà phệt do vậy em cũng thấy dễ áp dụng hơn ạ..
Thật tuyệt vời Cảm ơn 2 Thầy cảm ơn GPE!
 
Upvote 0
Hihi! Cảm ơn Anh Hai và Thầy nhiều ạ!
Cách của Anh Hai đúng là rất thuận tiện cho người không biết vba như Em nhưng thao tác cũng dài nhỉ mỗi lần cập nhật dữ liệu lại phải làm như vậy ạ!
Còn code của Thầy NDU đúng là em không hiểu gì @@ ,nhưng Thầy bảo rồi cứ Sub Main mà phệt do vậy em cũng thấy dễ áp dụng hơn ạ..
Thật tuyệt vời Cảm ơn 2 Thầy cảm ơn GPE!
Bạn chỉ làm "điều đó" 1 lần sau này muốn cập nhật thì bấm vào nút refresh trên thanh công cụ là được. Lưu ý là vùng dữ liệu phải được nằm trong câu truy vấn nhé.
 
Upvote 0
.........
Mã:
Sub Main()
  Dim aRes
  With Sheet1
    aRes = Join2DArray(.Range("E10:G19"), .Range("J10:M19"), .Range("O10:Q19"))
    .Range("E24").Resize(UBound(aRes, 1), UBound(aRes, 2)).Value = aRes
  End With
End Sub
............
Xin Chào Thầy!
Thưa thầy với trường hợp này của con thì có cách nào áp dụng được không ạ?
Nhiều file nhiều sheet vào một file.

Giả sử cụ thể con muốn dồn dữ liệu trong vùng A1:Q1000 của các file và Sheet dưới đấy:
A.xls (sheet3 đến Sheet20)
B.xls (sheet2 đến Sheet10)
C.xls (sheet4 đến Sheet8)

Vào File TongHop.xls tại Sheet2!T6

Các file này để chung trong cùng một 1 thư mục!
------------
Sở dĩ con muốn tổng hợp tất cả dữ liệu về một fle để tiện tính toán chung.(Cụ thể là các file chấm công và và file tính lương).
Mong thầy và các chuyên gia giúp đỡ để tìm cách giải quyết cho vấn đề trên ạ!
Xin cảm ơn!
 
Upvote 0
Xin Chào Thầy!
Thưa thầy với trường hợp này của con thì có cách nào áp dụng được không ạ?
Nhiều file nhiều sheet vào một file.

Giả sử cụ thể con muốn dồn dữ liệu trong vùng A1:Q1000 của các file và Sheet dưới đấy:
A.xls (sheet3 đến Sheet20)
B.xls (sheet2 đến Sheet10)
C.xls (sheet4 đến Sheet8)

Vào File TongHop.xls tại Sheet2!T6

Các file này để chung trong cùng một 1 thư mục!
------------
Sở dĩ con muốn tổng hợp tất cả dữ liệu về một fle để tiện tính toán chung.(Cụ thể là các file chấm công và và file tính lương).
Mong thầy và các chuyên gia giúp đỡ để tìm cách giải quyết cho vấn đề trên ạ!
Xin cảm ơn!
Đương nhiên là được
Đầu tiên hãy tham khảo hàm này:
Mã:
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
Chuyên dùng để lấy dữ liệu từ file đang đóng, trả về kết quả là 1 mảng
Kết hợp với những gì đã viết ở bài 3 thì hoàn toàn có thể giải quyết yêu cầu của bạn
---------------
Bạn tự mình nghiên cứu trước! Nếu như không được, vui lòng gửi mấy file A, B, C, TongHop gì đó lên đây để tôi làm giúp (vì tôi làm biếng cái vụ giả lập dữ liệu để test code lắm)
 
Upvote 0
Đương nhiên là được
............
Bạn tự mình nghiên cứu trước! Nếu như không được, vui lòng gửi mấy file A, B, C, TongHop gì đó lên đây để tôi làm giúp (vì tôi làm biếng cái vụ giả lập dữ liệu để test code lắm)
Cảm ơn Thầy! Khi gửi bài này con đã nghi nghi cái đoạn màu đỏ rồi nên cũng đã giải thích cụ thể hơn nhưng không ngờ Thầy nghiêm khắc hơn con nghĩ...hihi!+-+-+-+

Thưa thầy bài này thì con không thể áp dụng được nữa rồi!
Thầy xem file tổng hợp ạ! Sub Main con đã tự biên tự diễn ;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;---> kết quả là ..không thấy nó nhúc nhíc...hix:;;;:::

Những sheet màu đỏ trong các file A,B,C là những Sheet con muốn triết xuất dữ liệu sang file tổng hợp đó ạ.
Thầy xem file kèm và giúp đỡ con với ạ!
Cảm ơn Thầy!
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn Thầy! Khi gửi bài này con đã nghi nghi cái đoạn màu đỏ rồi nên cũng đã giải thích cụ thể hơn nhưng không ngờ Thầy nghiêm khắc hơn con nghĩ...hihi!+-+-+-+

Thưa thầy bài này thì con không thể áp dụng được nữa rồi!
Thầy xem file tổng hợp ạ! Sub Main con đã tự biên tự diễn ;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;---> kết quả là ..không thấy nó nhúc nhíc...hix:;;;:::

Những sheet màu đỏ trong các file A,B,C là những Sheet con muốn triết xuất dữ liệu sang file tổng hợp đó ạ.
Thầy xem file kèm và giúp đỡ con với ạ!
Cảm ơn Thầy!

Hi.... Hi...
Sửa sub Main thành vầy xem:
Mã:
Sub Main()
  Dim FileName As String, RangeAddress As String, SheetName As String
  Dim arr, aFiles, File, aRes
  Dim i As Long
  aFiles = Array("A", "B", "C")
  RangeAddress = "A1:Q1000"
  For Each File In aFiles  ''<---- ''Duyệt qua các file (3 file A, B, C)
    FileName = ThisWorkbook.Path & "\" & CStr(File) & ".xls"  ''<--- Đường dẫn file
    For i = 3 To 20  ''<---- Duyệt từ sheet3 đến Sheet20
      SheetName = "Sheet" & i ''<--- Tên Sheet
      arr = GetData(FileName, SheetName, RangeAddress, False, False) ''<--- Lấy dữ liệu từ file đóng
      If Not IsArray(aRes) Then  ''<--- Nếu aRes chưa có gì thì
        aRes = Join2DArray(arr)  ''<---- Nối mảng chỉ mình arr
      Else  ''<--- Ngược lại (aRes đã hình thành) thì
        aRes = Join2DArray(aRes, arr)  ''<--- Nối mảng gồm aRes và arr
      End If
    Next
  Next
  Sheet2.Range("T6").Resize(UBound(aRes, 1), UBound(aRes, 2)).Value = aRes
End Sub
--------------------
Nói thêm: Nếu tất cả các file của bạn đều có cùng cấu trúc + CSDL chuẩn thì tôi sẽ có cách làm khác (nhanh hơn)
 
Lần chỉnh sửa cuối:
Upvote 0
Hi.... Hi...
Sửa sub Main thành vầy xem:
Mã:
Sub Main()
  Dim FileName As String, RangeAddress As String, SheetName As String
  Dim arr, aFiles, File, aRes
  Dim i As Long
  aFiles = Array("A", "B", "C")
  RangeAddress = "A1:Q1000"
  For Each File In aFiles  ''<---- ''Duyệt qua các file (3 file A, B, C)
    FileName = ThisWorkbook.Path & "\" & CStr(File) & ".xls"  ''<--- Đường dẫn file
    For i = 3 To 20  ''<---- Duyệt từ sheet3 đến Sheet20
      SheetName = "Sheet" & i ''<--- Tên Sheet
      arr = GetData(FileName, SheetName, RangeAddress, False, False) ''<--- Lấy dữ liệu từ file đóng
      If Not IsArray(aRes) Then  ''<--- Nếu aRes chưa có gì thì
        aRes = Join2DArray(arr)  ''<---- Nối mảng chỉ mình arr
      Else  ''<--- Ngược lại (aRes đã hình thành) thì
        aRes = Join2DArray(aRes, arr)  ''<--- Nối mảng gồm aRes và arr
      End If
    Next
  Next
  Sheet2.Range("T6").Resize(UBound(aRes, 1), UBound(aRes, 2)).Value = aRes
End Sub
--------------------
Nói thêm: Nếu tất cả các file của bạn đều có cùng cấu trúc + CSDL chuẩn thì tôi sẽ có cách làm khác (nhanh hơn)

hihi! Cảm ơn Thầy!
Đúng là tất cả các file đồng nhất về cấu trúc Thầy ạ! Sở dĩ vì sao phải nhiều file nhiều Sheet là vì chia theo bộ phận và chia theo tổ ạ!
Nếu Thầy còn cách nào nhanh hơn mà không khiến thầy QUÁ CỰC thì Thầy giúp con nhé!^^
Cứ nhanh mà lại hiệu quả là Con thích lắm ạ!
Cảm ơn Thầy!
 
Upvote 0
Hi.... Hi...
Sửa sub Main thành vầy xem:
Mã:
Sub Main()
  Dim FileName As String, RangeAddress As String, SheetName As String
  Dim arr, aFiles, File, aRes
  Dim i As Long
  aFiles = Array("A", "B", "C")
  RangeAddress = "A1:Q1000"
  For Each File In aFiles  ''<---- ''Duyệt qua các file (3 file A, B, C)
    FileName = ThisWorkbook.Path & "\" & CStr(File) & ".xls"  ''<--- Đường dẫn file
    For i = 3 To 20  ''<---- Duyệt từ sheet3 đến Sheet20
      SheetName = "Sheet" & i ''<--- Tên Sheet
      arr = GetData(FileName, SheetName, RangeAddress, False, False) ''<--- Lấy dữ liệu từ file đóng
      If Not IsArray(aRes) Then  ''<--- Nếu aRes chưa có gì thì
        aRes = Join2DArray(arr)  ''<---- Nối mảng chỉ mình arr
      Else  ''<--- Ngược lại (aRes đã hình thành) thì
        aRes = Join2DArray(aRes, arr)  ''<--- Nối mảng gồm aRes và arr
      End If
    Next
  Next
  Sheet2.Range("T6").Resize(UBound(aRes, 1), UBound(aRes, 2)).Value = aRes
End Sub
--------------------
Nói thêm: Nếu tất cả các file của bạn đều có cùng cấu trúc + CSDL chuẩn thì tôi sẽ có cách làm khác (nhanh hơn)

Thưa Thầy,Con đã test thử tình hình là:
Xin lỗi Thầy do Con diễn đạt yêu cầu chưa rõ ràng nên kết quả Thầy làm chưa đúng với ý của Con.
Cụ thể là thế này Thầy ạ!
Về cấu trúc CSDL của các file và các Sheets thì giống hệt nhau.
Nhưng ý con muốn là:
1. Nơi cần lấy dữ liệu: A1:Q100
+Trong File A.xls chỉ lấy dữ liệu từ Sheet3 đến Sheet20
+Trong File B.xls chỉ lấy dữ liệu từ Sheet2 đến Sheet10
+Trong File C.xls chỉ lấy dữ liệu từ Sheet4 đến Sheet8
Còn các Sheet khác dữ liệu nó như thế nào thì không cần quan tâm đến đây
2. Và khi lấy dữ liệu vào File tổng hợp thì các dòng có dữ liệu sẽ dồn lại (loại bỏ các dòng trống_dòng không có 1 chút dữ liệu nào àNhư thầy đã làm đấy ạ).
Còn về cột thì không dồn giống dòng mà dữ liệu ở cột nào thì vẫn để nguyên cột đó. Nghĩa là không xóa những cột trống đi ạ.
Cụ thể ví dụ minh họa dữ liệu cần triết xuất ra giống như file đính kèm.
Thầy sửa lại giúp con với ạ & Thầy cũng chú ý giữ gìn sức khỏe Thầy nhé!
Cảm ơn Thầy rất nhiều!
 

File đính kèm

Upvote 0
1. Nơi cần lấy dữ liệu: A1:Q100
+Trong File A.xls chỉ lấy dữ liệu từ Sheet3 đến Sheet20
+Trong File B.xls chỉ lấy dữ liệu từ Sheet2 đến Sheet10
+Trong File C.xls chỉ lấy dữ liệu từ Sheet4 đến Sheet8

Sửa Sub Main thành vầy:
Mã:
Sub Main()
  Dim FileName As String, RangeAddress As String, SheetName As String
  Dim arr, aRes, aResA, aResB, aResC
  Dim i As Long
  RangeAddress = "A1:Q1000"
  [COLOR=#0000cd]'Lay du lieu o file A.xls, tu Sheet3 --> Sheet20
  FileName = ThisWorkbook.Path & "\A.xls"
  For i = 3 To 20
    SheetName = "Sheet" & i
    arr = GetData(FileName, SheetName, RangeAddress, False, False)
    If Not IsArray(aResA) Then
      aResA = Join2DArray(arr)
    Else
      aResA = Join2DArray(aResA, arr)
    End If
  Next[/COLOR]
 [COLOR=#ff8c00] 'Lay du lieu o file B.xls, tu Sheet2 --> Sheet10
  FileName = ThisWorkbook.Path & "\B.xls"
  For i = 2 To 10
    SheetName = "Sheet" & i
    arr = GetData(FileName, SheetName, RangeAddress, False, False)
    If Not IsArray(aResB) Then
      aResB = Join2DArray(arr)
    Else
      aResB = Join2DArray(aResB, arr)
    End If
  Next[/COLOR]
[COLOR=#ff0000]  'Lay du lieu o file C.xls, tu Sheet4 --> Sheet8
  FileName = ThisWorkbook.Path & "\C.xls"
  For i = 4 To 8
    SheetName = "Sheet" & i
    arr = GetData(FileName, SheetName, RangeAddress, False, False)
    If Not IsArray(aResC) Then
      aResC = Join2DArray(arr)
    Else
      aResC = Join2DArray(aResC, arr)
    End If
  Next[/COLOR]
  aRes = Join2DArray(aResA, aResB, aResC) ''<--- Join 3 ket qua lai
  Sheet2.Range("T6").Resize(UBound(aRes, 1), UBound(aRes, 2)).Value = aRes
End Sub
 

File đính kèm

Upvote 0
Cảm ơn Thầy!
Con đã Test thử thấy rất chuẩn theo ý mình!
---
Thầy trả lời nhanh thật giữa 2 thời hỏi và trả lời chỉ mất vài phút...@@!
Với con chắc ngồi chếp không toàn bộ code của Thầy trong bài này hết ngày cũng chửa chắc đã xong.
Những dòng chú thích bên cạnh các dòng code rất hữu ích khiến Con cũng dần dần hình dung được thuật toán! ^^
Một lần nữa rất cảm ơn Thầy và GPE đã giúp Con hoàn thành đề tài này...hihi!
 
Upvote 0
Cảm ơn Thầy!
Con đã Test thử thấy rất chuẩn theo ý mình!
---
Thầy trả lời nhanh thật giữa 2 thời hỏi và trả lời chỉ mất vài phút...@@!

Tôi thường tâm sự trên GPE là TÔI CÓ ĐỒ NGHỀ mà (những code thường dùng luôn được lưu sẵn)
Vậy nên bất cứ yêu cầu nào, miễn "khớp" với 1 loại "đồ nghề" nào đó thì tôi lập tức moi ra ráp vào (chỉ chỉnh sửa tí)
Ai rảnh đâu mà mỗi thứ mỗi viết
(Thậm chí tại thời điểm này, bảo tôi viết lại toàn bộ hàm Join2DArray tôi cũng chả nhớ....)
Ẹc.... Ẹc...
---------------
Bạn cũng nên học theo cách này. Ví dụ:
- Thấy hàm GetData có thể dùng sau này ---> Lưu thành 1 file (tên gì miễn là bạn có thể nhớ và tìm lại được)
- Thấy hàm Join2DArray có thể dùng sau này ---> Lưu thành 1 file (tên gì miễn là bạn có thể nhớ và tìm lại được)
vân vân....
 
Upvote 0
Ah!Ra là vậy!
hix!Nhưng Khổ nỗi là Con chưa đủ khả năng để hiểu những cái Hàm tự tạo kiể đó Thầy ạ!
Con chỉ thích cái Sub Main của Thầy thôi ạ! Cứ bài nào tương tự là cứ bê hết vào rồi cũng chỉnh sửa tí ti... hohoho
Còn những cái khác thì nhìn vào Con có cảm giác bị tàu hoả nhập ma luôn! :v
Nhưng dù sao con cũng thấy thích dần môn này rồi đó ạ!
Cảm ơn Thầy đã chỉ giáo!
 
Upvote 0

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

Back
Top Bottom