Cập nhật dữ liệu không có từ một File khác.

Liên hệ QC

huy vu

Thành viên hoạt động
Tham gia
29/2/12
Bài viết
164
Được thích
1
Em chào các anh/chị trên giaiphapexcel.

Em có 1 bài toán sau, mong các anh/chị giúp.

Em có 2 File Excel: File A và File B (có thể không cùng 1 Folder).
Cấu trúc các trường của file A và File B giống hệt nhau. Gồm các trường để quản lý dữ liệu khách hàng.

File A đang mở, File B đóng.

Tại File A e muốn 1 đoạn code để cập nhật dữ liệu từ File B vào. Dữ liệu cập nhật là dữ liệu không có trong File A mà có trong File B. Cụ thể là copy những khách hàng mới từ file B vào File A, tức là căn cứ trường số CMT, những số chứng minh thư nào mà có trong File B mà không có trong File A thì copy dữ liệu vào.

Em có 2 File đính kèm, và cả phần mô tả

Mong các thành viên giúp đỡ !
 

File đính kèm

  • Update.rar
    16.5 KB · Đọc: 46
Cùng ý tưởng với mình, nhưng mình cũng không làm được, chỉ chờ các cao thủ làm xong thì học hỏi thôi.hjhj
 
Cùng ý tưởng với mình, nhưng mình cũng không làm được, chỉ chờ các cao thủ làm xong thì học hỏi thôi.hjhj
Cảm ơn bạn đã quan tâm, hy vọng tôi và bạn sẽ có giải pháp.

Bổ sung thêm ý là 2 file có thể không cùng Folder, nên code có inputbox để chọn file B là tổng quát nhất.

Xin cảm ơn!
 
Cảm ơn bạn đã quan tâm, hy vọng tôi và bạn sẽ có giải pháp.

Bổ sung thêm ý là 2 file có thể không cùng Folder, nên code có inputbox để chọn file B là tổng quát nhất.

Xin cảm ơn!
Code cùi:
[GPECODE=vb]Sub CopyandPaste()
Dim i As Long, t As Long, FileOpen As String
Dim WbB As Workbook, WbA As Workbook
Set WbA = Workbooks("A.xls")
FileOpen = Application.GetOpenFilename("Excel Files (*.xls*), *.xls")
Workbooks.Open(FileOpen, , , , "").Activate
Set WbB = Workbooks("B.xls")
WbA.Activate
For i = 2 To [A65536].End(xlUp).Row
For t = 2 To WbB.Sheets(1).[A65536].End(xlUp).Row
If Cells(i, 4) = WbB.Sheets(1).Cells(t, 4) Then
WbB.Sheets(1).Cells(t, 4).Interior.ColorIndex = 7
End If
Next
Next
WbB.Activate
For i = 2 To [A65536].End(xlUp).Row
If Cells(i, 4).Interior.ColorIndex <> 7 Then
Cells(i, 1).EntireRow.Copy WbA.Sheets(1).[A1].End(xlDown).Offset(1, 0)
End If
Next
Range([A2], [A65536].End(xlUp)).EntireRow.Interior.ColorIndex = xlNone
End Sub[/GPECODE]
Bạn chạy Code đến lúc nó hiện hộp thoại thì bạn chọn đến đường dẫn đang lưu File B rồi mở File B lên nhé.
 
Lần chỉnh sửa cuối:
Code cùi:
[GPECODE=vb]Sub CopyandPaste()
Dim i As Long, t As Long, FileOpen As String
Dim WbB As Workbook, WbA As Workbook
Set WbA = Workbooks("A.xls")
FileOpen = Application.GetOpenFilename("Excel Files (*.xls*), *.xls")
Workbooks.Open(FileOpen, , , , "").Activate
......[/GPECODE]
Bạn chạy Code đến lúc nó hiện hộp thoại thì bạn chọn đến đường dẫn đang lưu File B rồi mở File B lên nhé.
Cảm ơn bạn, tuy nhiên đâu phải là copy những ô mầu VÀNG đâu, tôi bôi vàng dữ liệu có trong file B để phân biệt là nó chưa có trong file A thôi. Vì rõ ràng, như vậy phải mở file B lên, bôi mầu những dữ liệu chưa có, xong quay lại A làm code, như thế chi bằng copy tay cho xong.

Bạn xem có giải pháp khác.
Cảm ơn bạn đã quan tâm.
 
Cảm ơn bạn, tuy nhiên đâu phải là copy những ô mầu VÀNG đâu, tôi bôi vàng dữ liệu có trong file B để phân biệt là nó chưa có trong file A thôi. Vì rõ ràng, như vậy phải mở file B lên, bôi mầu những dữ liệu chưa có, xong quay lại A làm code, như thế chi bằng copy tay cho xong.

Bạn xem có giải pháp khác.
Cảm ơn bạn đã quan tâm.
Tôi làm theo như đề bài bạn nêu mà, không phải bạn mong muốn vậy sao? Vậy bạn vẫn muốn để màu vàng tại File B phải không? Bạn thử xài Code này (Sửa lại tí xíu):
[GPECODE=vb]Sub CopyandPaste()
Dim i As Long, t As Long, FileOpen As String
Dim WbB As Workbook, WbA As Workbook
Set WbA = Workbooks("A.xls")
FileOpen = Application.GetOpenFilename("Excel Files (*.xls*), *.xls")
Workbooks.Open(FileOpen, , , , "").Activate
Set WbB = Workbooks("B.xls")
WbA.Activate
For i = 2 To [A65536].End(xlUp).Row
For t = 2 To WbB.Sheets(1).[A65536].End(xlUp).Row
If Cells(i, 4) = WbB.Sheets(1).Cells(t, 4) Then
WbB.Sheets(1).Cells(t, 4).Interior.ColorIndex = 7
End If
Next
Next
WbB.Activate
For i = 2 To [A65536].End(xlUp).Row
If Cells(i, 4).Interior.ColorIndex <> 7 Then
Cells(i, 1).EntireRow.Copy WbA.Sheets(1).[A1].End(xlDown).Offset(1, 0)
End If
Next
For i = 2 To [A65536].End(xlUp).Row
If Cells(i, 4).Interior.ColorIndex = 7 Then
Cells(i, 4).EntireRow.Interior.ColorIndex = xlNone
End If
Next
WbA.Activate
End Sub[/GPECODE]
 
Có lẽ bạn chưa hiểu ý tôi rồi, không phải là tôi copy những dòng mầu vàng từ file B sang file A. Tôi bôi vàng là để dễ hình dung thôi, còn thực tế File B đâu có màu sắc gì đâu. Cái căn cứ ở đây là so sánh các số CMT, số CMT nào có trong File B mà không có trong file A thì cập nhật vào File A.
Cảm ơn bạn.
 
Tại File A e muốn 1 đoạn code để cập nhật dữ liệu từ File B vào. Dữ liệu cập nhật là dữ liệu không có trong File A mà có trong File B. Cụ thể là copy những khách hàng mới từ file B vào File A, tức là căn cứ trường số CMT, những số chứng minh thư nào mà có trong File B mà không có trong File A thì copy dữ liệu vào.
Ủa, tôi copy File B vào File A những khách hàng (File B có mà File A không có). Bạn xem kỹ lại sau khi chạy Code của tôi xem. Có phải là như vậy không?
Có lẽ bạn chưa hiểu ý tôi rồi, không phải là tôi copy những dòng mầu vàng từ file B sang file A. Tôi bôi vàng là để dễ hình dung thôi, còn thực tế File B đâu có màu sắc gì đâu. Cái căn cứ ở đây là so sánh các số CMT, số CMT nào có trong File B mà không có trong file A thì cập nhật vào File A.
Cảm ơn bạn.
Sao mâu thuẫn thế nhỉ? Ở #1 thì bạn muốn Copy trong File B là những khách hàng không có trong File A ? Chẳng phải là những dòng màu vàng trong File B là những khách hàng không có trong File A sao? (Tôi đâu có quan tâm những dòng màu vàng đâu, chẳng qua là lúc Copy những khách hàng có dòng màu vàng ở File B thì nó "Copy" luôn màu vàng từ File B sang File A mà thôi.)
 
Ủa, tôi copy File B vào File A những khách hàng (File B có mà File A không có). Bạn xem kỹ lại sau khi chạy Code của tôi xem. Có phải là như vậy không?

Sao mâu thuẫn thế nhỉ? Ở #1 thì bạn muốn Copy trong File B là những khách hàng không có trong File A ? Chẳng phải là những dòng màu vàng trong File B là những khách hàng không có trong File A sao? (Tôi đâu có quan tâm những dòng màu vàng đâu, chẳng qua là lúc Copy những khách hàng có dòng màu vàng ở File B thì nó "Copy" luôn màu vàng từ File B sang File A mà thôi.)
Cảm ơn ban. Tôi chạy code thấy ok, để kiểm tra thêm.
Có giải pháp ADO ko cần mở file B, mong các tv giúp thêm để hoàn thiện hơn.
 
Có giải pháp ADO ko cần mở file B, mong các tv giúp thêm để hoàn thiện hơn.

Không cần ADO làm gì. Có kết quả là được. Khâu ADO nếu có cho "oai" (và cũng để tham khảo cho chương trình khác). Tuy nhiên, nếu biết tên file cần lấy dữ liệu, có thể mở được nó thì cứ mở.

Nếu có thể thì:
- Mở file B
- Chép toàn bộ dữ liệu của sheet của file B vô 1 sheet trắng của file A (có thể tạo mới và đặt tên cho nó).
- Đóng file B
- Tuỳ ý xử lý cái dữ liệu vừa chép vô
 
Cảm ơn ban. Tôi chạy code thấy ok, để kiểm tra thêm.
Có giải pháp ADO ko cần mở file B, mong các tv giúp thêm để hoàn thiện hơn.

Lý do tại sao lại không muốn mở file B?

Có hai cách sử dụng ADO, tuỳ theo lý do trên mà sử dụng cách nào:

1. Dùng một lệnh sql đọc cả hai bảng, lọc ra cái có trong B mà không có trong A. Ghi kết quả vào A. Vì cách này phải nối với file đang mở, file A, cho nên chỉ chạy được một đôi lần, nếu chạy liên tục cho nhiều file Bs thì sẽ bị crash Excel.

2. Dùng một lệnh sql đọc bảng B. Duyệt recordset để ghi những dữ liệu cần thiết vào A. Cách này dài dòng hơn nhưng an toàn hơn nếu phải làm việc trên nhiều file Bs.
 
Không cần ADO làm gì. Có kết quả là được. Khâu ADO nếu có cho "oai" (và cũng để tham khảo cho chương trình khác). Tuy nhiên, nếu biết tên file cần lấy dữ liệu, có thể mở được nó thì cứ mở.

Nếu có thể thì:
- Mở file B
- Chép toàn bộ dữ liệu của sheet của file B vô 1 sheet trắng của file A (có thể tạo mới và đặt tên cho nó).
- Đóng file B
- Tuỳ ý xử lý cái dữ liệu vừa chép vô
Việc chép dữ liệu vào tôi có thể làm tuy nhiên chả làm j tự nhiên dữ liệu bị nhân đôi lên, có vài chục nghìn bản ghi thì ì ạch lắm. Vậy tôi nghĩ ra tình huống chỉ chép vào những dữ liệu ko có.

Có 1 cách tôi thấy hơi cùi là copy tất cả B vào A rồi remove duplicate.
 
Lý do tại sao lại không muốn mở file B?

Có hai cách sử dụng ADO, tuỳ theo lý do trên mà sử dụng cách nào:

1. Dùng một lệnh sql đọc cả hai bảng, lọc ra cái có trong B mà không có trong A. Ghi kết quả vào A. Vì cách này phải nối với file đang mở, file A, cho nên chỉ chạy được một đôi lần, nếu chạy liên tục cho nhiều file Bs thì sẽ bị crash Excel.

2. Dùng một lệnh sql đọc bảng B. Duyệt recordset để ghi những dữ liệu cần thiết vào A. Cách này dài dòng hơn nhưng an toàn hơn nếu phải làm việc trên nhiều file Bs.
Thực ra để lấy dữ liệu thì kiểu gì cũng phải mở, nên mở rồi đóng cũng chỉ trong nháy mắt.
Cách nào an toàn thì làm anh ơi. Anh giúp em với ạ.
 
...
Có 1 cách tôi thấy hơi cùi là copy tất cả B vào A rồi remove duplicate.

Nói thật, nếu là tôi thì tôi chuộng cách này thay vì code kiếc. Cùi hay cụt đối với tôi không thành vấn đề. Mèo trắng hay đen đều bắt được chuột. Tôi chỉ chọn con mèo ít ăn vụng thôi.
 
Nói thật, nếu là tôi thì tôi chuộng cách này thay vì code kiếc. Cùi hay cụt đối với tôi không thành vấn đề. Mèo trắng hay đen đều bắt được chuột. Tôi chỉ chọn con mèo ít ăn vụng thôi.
Cảm ơn anh đã động viên, dù sao thì mèo trắng cũng cảm giác vẫn thích hơn.
A chỉ giáo dùng sql với ạ.
 
Thực ra để lấy dữ liệu thì kiểu gì cũng phải mở, nên mở rồi đóng cũng chỉ trong nháy mắt.
Cách nào an toàn thì làm anh ơi. Anh giúp em với ạ.
Copy code này vào chạy thử
PHP:
Sub abc()
Dim Arr(), i, j, k, chk
chk = Application.FindFile
If chk = False Then End
With ActiveWorkbook.ActiveSheet
   Arr = .Range("A2", .[M65536].End(3)).Value
   .Parent.Close False
End With
With Sheet1
   .[A65536].End(3)(2).Resize(UBound(Arr), 13) = Arr
   .[a1].CurrentRegion.RemoveDuplicates 4, 1
   .Range("A2", .[A65536].End(3)) = [row(a:a)]
End With
End Sub
 
Cảm ơn ban. Tôi chạy code thấy ok, để kiểm tra thêm.
Có giải pháp ADO ko cần mở file B, mong các tv giúp thêm để hoàn thiện hơn.
Vẫn phải mở File B lên nhưng không phải mở bằng thủ công (Với điều kiện biết chắc File B đang nằm ở đường dẫn nào) và tự động Close File B sau khi Copy xong.
 
Cảm ơn anh đã động viên, dù sao thì mèo trắng cũng cảm giác vẫn thích hơn.
A chỉ giáo dùng sql với ạ.

Mèo trắng hay đen: biết thế nào bạn cũng chọn cái này. Chỉ chú trọng màu mè và quên để ý kế đó có điều kiện mèo ăn vụng.

sql - có nhiều dạng:

1. Nếu chỉ làm kiểu "append and remove duplicates" thì
SELECT F1, F2, ... In [bảng 1]
Union
SELECT F1, F2, ... In [bảng 2]

2. Nếu muốn lấy các dữ liệu ở bảng 2 mà chưa có trong bảng 1
SELECT F1, F2, ... In [bảng 2]
where not exists
(SELECT F1 In [bảng 1] where [bảng 1].F1 = [bảng 2].F1)

3. Cũng ý tưởng giống 2 nhưng dùng lefft join có thể nhanh hơn. Nhưng cấu lệnh rắc rối hơn. Chạy qua bên bài "đố vui về..." Hay "những bài tập căn bản..." Có cả đống.
 
Mèo trắng hay đen: biết thế nào bạn cũng chọn cái này. Chỉ chú trọng màu mè và quên để ý kế đó có điều kiện mèo ăn vụng.

sql - có nhiều dạng:

1. Nếu chỉ làm kiểu "append and remove duplicates" thì
SELECT F1, F2, ... In [bảng 1]
Union
SELECT F1, F2, ... In [bảng 2]

2. Nếu muốn lấy các dữ liệu ở bảng 2 mà chưa có trong bảng 1
SELECT F1, F2, ... In [bảng 2]
where not exists
(SELECT F1 In [bảng 1] where [bảng 1].F1 = [bảng 2].F1)

3. Cũng ý tưởng giống 2 nhưng dùng lefft join có thể nhanh hơn. Nhưng cấu lệnh rắc rối hơn. Chạy qua bên bài "đố vui về..." Hay "những bài tập căn bản..." Có cả đống.
Anh có lòng giúp thì giúp hoàn thiện đoạn code, chứ người mới học như tôi e là càng đọc thì càng như di vào rừng rậm.
 
Mã:
Function Update1(ByVal FileName$) As Long
    Dim ConnStr$, n&, SQLStr$, cnn As ADODB.Connection, rst As ADODB.Recordset
    On Error GoTo lbEndSub
    Sheet1.Activate
    n = Range("B" & Columns(1).Rows.Count).End(xlUp).Row + 1
    '?????
    Range("B" & n, "B" & Columns(1).Rows.Count).EntireRow.Delete


    
    ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
               "Data Source=" & FileName & _
                ";Extended Properties=""Excel 12.0;HDR=YES;IMEX=1"";"
    Set cnn = New ADODB.Connection
    cnn.Open ConnStr
    
    
    Set rst = New ADODB.Recordset
    SQLStr = "SELECT DISTINCT * FROM [Sheet1$B1:M1000000] b WHERE b.CMND_HC NOT IN (SELECT a.CMND_HC FROM " & _
            "[Excel 12.0;HDR=YES;IMEX=1;DATABASE=" & _
              ThisWorkbook.FullName & "].[sheet1$] a)"
    
   
    rst.Open SQLStr, cnn
    Range("B" & n).CopyFromRecordset rst
    Range("B" & n, "M" & Range("B" & Columns(1).Rows.Count).End(xlUp).Row).RemoveDuplicates 3, 0
    Update1 = Range("B" & Columns(1).Rows.Count).End(xlUp).Row - n + 1
    
    Range("A2").AutoFill Range("A2:A" & (n + Update1 - 1)), xlFillSeries
lbEndSub:
    If Not rst Is Nothing Then
        If rst.State = adStateOpen Then rst.Close
        Set rst = Nothing
    End If
    If Not cnn Is Nothing Then
        If cnn.State = adStateOpen Then cnn.Close
        Set cnn = Nothing
    End If
    If Err.Number <> 0 Then MsgBox Err.Number & ": " & Err.Description, vbCritical
        
    
End Function


Function Update2(ByVal FileName$) As Long
    Dim ConnStr$, SQLStr$, cnn As ADODB.Connection, rst As ADODB.Recordset, Fld As Field, ar1(), ar2()
    Dim n&, i&, j&, k&, Chk As Boolean, PrevousRecord$
    On Error GoTo lbEndSub
    ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
               "Data Source=" & FileName & _
                ";Extended Properties=""Excel 12.0;HDR=YES;IMEX=1"";"
    Set cnn = New ADODB.Connection
    cnn.Open ConnStr
    
    Set rst = New ADODB.Recordset
    SQLStr = "SELECT DISTINCT * FROM [sheet1$B1:M1000000] ORDER BY CMND_HC"
    rst.Open SQLStr, cnn
    
    n = Range("B" & Columns(1).Rows.Count).End(xlUp).Row
    i = 1
    ar1 = Sheet1.Range("B2:M" & n)
    ReDim ar2(1 To 100000, 1 To UBound(ar1, 2))
    
    Do While Not rst.EOF
        Chk = False
        For i = 1 To UBound(ar1)
            If rst.Fields("CMND_HC").Value = PrevousRecord Then
                Chk = True
                Exit For
            Else
                For k = 1 To UBound(ar1)
                    If rst.Fields("CMND_HC").Value = ar1(k, 3) Then
                        Chk = True
                        Exit For
                    End If
                Next
            End If
        Next
        If Not Chk Then
            j = j + 1
            i = 1
            For Each Fld In rst.Fields
                ar2(j, i) = Fld.Value
                i = i + 1
            Next
            PrevousRecord = ar2(j, 3)
        End If
        rst.MoveNext
    Loop
    Range("B" & (n + 1)).Resize(j, UBound(ar1, 2)) = ar2
    Update2 = j
    Range("A2").AutoFill Range("A2:A" & (n + j)), xlFillSeries
lbEndSub:
    If Not rst Is Nothing Then
        If rst.State = adStateOpen Then rst.Close
        Set rst = Nothing
    End If
    If Not cnn Is Nothing Then
        If cnn.State = adStateOpen Then cnn.Close
        Set cnn = Nothing
    End If
    If Err.Number <> 0 Then MsgBox Err.Number & ": " & Err.Description, vbCritical
End Function


Sub test()
    Dim FileName$, FDlg As FileDialog
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Set FDlg = Application.FileDialog(msoFileDialogFilePicker)
    FDlg.AllowMultiSelect = False
    If FDlg.Show = 0 Then GoTo lbEndSub
    FileName = FDlg.SelectedItems(1)
    
    Application.ScreenUpdating = True


    MsgBox Update1(FileName) & " records have been appended."
lbEndSub:
    Set FDlg = Nothing
    Application.ScreenUpdating = True
    Application.EnableEvents = True
End Sub
Có thể dùng Update1 hoặc Update2, bài này khó chịu ở chỗ file B có nhiều record trùng nhau nên ADO có lẽ không hiệu quả.
 
Web KT
Back
Top Bottom