So sánh 2 sheet và trả về kết quả sai lệch

Liên hệ QC

vuongphuc

Thành viên mới
Tham gia
3/11/21
Bài viết
4
Được thích
0
Mình có 2 sheet dữ liệu và một sheet so sánh sai lệch, mình thường làm làm bằng Pivot Table, nhưng thao tác phải lặp lại mỗi khi thay đổi dữ liệu. Mình nhờ các bạn viết giúp code VBA để mình so sánh được nhanh và hiệu quả hơn. Trân trọng cảm ơn.
Chi tiết mẫu theo file đính kèm
 

File đính kèm

Mình có 2 sheet dữ liệu và một sheet so sánh sai lệch, mình thường làm làm bằng Pivot Table, nhưng thao tác phải lặp lại mỗi khi thay đổi dữ liệu. Mình nhờ các bạn viết giúp code VBA để mình so sánh được nhanh và hiệu quả hơn. Trân trọng cảm ơn.
Chi tiết mẫu theo file đính kèm
1/ Nếu chứng từ nào bằng nhau giữa 2 sheet thì không kê ra ở sheet so sánh? Đúng lý ra phải kê lên hết dù hiệu số = 0
2/ Tại sao ở sheet2, chứng từ không có đuôi /GNT?
 
Mình có 2 sheet dữ liệu và một sheet so sánh sai lệch, mình thường làm làm bằng Pivot Table, nhưng thao tác phải lặp lại mỗi khi thay đổi dữ liệu. Mình nhờ các bạn viết giúp code VBA để mình so sánh được nhanh và hiệu quả hơn. Trân trọng cảm ơn.
Chi tiết mẫu theo file đính kèm
Góp vui, bạn dùng thử trong khi chờ các giải pháp khác.
Hãy nhấn nút SO SANH ở sh3 và xem kết quả
Mã:
Sub SoSanh()
Dim i&, j&, k&, Lr1&, Lr2&, n&, m&
Dim Arr1(), Arr2(), KQ(), KETQUA()
Dim Dic As Object
With Sheet1
Lr1 = .Cells(Rows.Count, 1).End(xlUp).Row
Arr1 = .Range("A2:C" & Lr1).Value
R1 = UBound(Arr1)
End With
With Sheet2
Lr2 = .Cells(Rows.Count, 1).End(xlUp).Row
Arr2 = .Range("A2:C" & Lr2).Value
R2 = UBound(Arr2)
End With
ReDim KQ(1 To R1 + R2, 1 To 5)
Set Dic = CreateObject("scripting.dictionary")

For i = 1 To R1
    Keys = Application.Substitute(Trim(Arr1(i, 1)), "/GNT", "")
    If Not Dic.Exists(Keys) Then
        t = t + 1
        Dic.Add (Keys), t
        KQ(t, 1) = Format(Keys, "0000#")
        KQ(t, 2) = Arr1(i, 2)
        KQ(t, 3) = Arr1(i, 3)
    Else
        k = Dic.Item(Keys)
        KQ(k, 2) = Arr1(i, 2)
        KQ(k, 3) = KQ(k, 3) + Arr1(i, 3)
    End If
        KQ(t, 5) = KQ(t, 3) - KQ(t, 4)
Next i
For j = 1 To R2
    Temp = Trim(Arr2(j, 1))
    If Not Dic.Exists(Temp) Then
        t = t + 1
        KQ(t, 1) = Format(Temp, "0000#")
        KQ(t, 2) = Arr2(j, 2)
        KQ(t, 4) = Arr2(j, 3)
    Else
        k = Dic.Item(Temp)
        KQ(k, 2) = Arr2(j, 2)
        KQ(k, 4) = KQ(k, 4) + Arr2(j, 3)
        KQ(k, 5) = KQ(k, 3) - KQ(k, 4)
    End If
        KQ(t, 5) = KQ(t, 3) - KQ(t, 4)
Next j
ReDim KETQUA(1 To t, 1 To 5)
For n = 1 To t
    If KQ(n, 3) <> KQ(n, 4) Then
        Z = Z + 1
        For m = 1 To 5
            KETQUA(Z, m) = KQ(n, m)
        Next m
            KETQUA(Z, 1) = Format(KETQUA(Z, 1), "0000#")
    End If
Next n
If Z Then
Sheet3.Cells(2, 1).Resize(Z + 5, 5).ClearContents
Sheet3.Cells(2, 1).Resize(Z, 5) = KETQUA
End If
Set Dic = Nothing
MsgBox " Xong"
End Sub
anh chị em có ghé xem xin góp ý để code được ngắn gọn và xử lý được hết các trường hợp xảy ra. Trân trọng.
 

File đính kèm

Tôi đề nghị vẫn phải kê các chứng từ khớp số liệu vì có như thế dữ liệu của cột Tổng sheet1 và Tổng sheet2 mới toàn vẹn và ta cũng biết được chứng từ nào khớp.
Rich (BB code):
Sub SS2Sheet()
Dim arrS1, arrS2, arrRsl, Dic As Object
Dim i&, k&, dKey$

    arrS1 = Sheet1.Range("A2:C" & Sheet1.Range("A" & Rows.Count).End(xlUp).Row)
    arrS2 = Sheet2.Range("A2:C" & Sheet2.Range("A" & Rows.Count).End(xlUp).Row)
    Set Dic = CreateObject("Scripting.Dictionary")
    ReDim arrRsl(1 To UBound(arrS1) + UBound(arrS2), 1 To 5)
    For i = 1 To UBound(arrS1)
        dKey = arrS1(i, 1)
        If Not Dic.Exists(dKey) Then
            k = k + 1
            Dic.Add dKey, k
            arrRsl(k, 1) = dKey
            arrRsl(k, 2) = arrS1(i, 2)
            arrRsl(k, 3) = arrS1(i, 3)
            arrRsl(k, 4) = 0
            arrRsl(k, 5) = arrS1(i, 3)
        Else
            arrRsl(Dic.Item(dKey), 3) = arrRsl(Dic.Item(dKey), 3) + arrS1(i, 3)
            arrRsl(Dic.Item(dKey), 5) = arrRsl(Dic.Item(dKey), 5) + arrS1(i, 3)
        End If
    Next
    For i = 1 To UBound(arrS2)
        dKey = arrS2(i, 1) & "/GNT"
        If Not Dic.Exists(dKey) Then
            k = k + 1
            Dic.Add dKey, k
            arrRsl(k, 1) = dKey
            arrRsl(k, 2) = arrS2(i, 2)
            arrRsl(k, 3) = 0
            arrRsl(k, 4) = arrS2(i, 3)
            arrRsl(k, 5) = -arrS2(i, 3)
        Else
            arrRsl(Dic.Item(dKey), 4) = arrRsl(Dic.Item(dKey), 4) + arrS2(i, 3)
            arrRsl(Dic.Item(dKey), 5) = arrRsl(Dic.Item(dKey), 5) - arrS2(i, 3)
        End If
    Next
    Sheet3.Range("A2").Resize(UBound(arrS1) + UBound(arrS2), 5).ClearContents
    Sheet3.Range("A2").Resize(k, 5) = arrRsl
    Set Dic = Nothing
End Sub

@HUONGHCKT: Ở cột 5 mảng kết quả, nếu là dữ liệu sheet1 thì cộng, sheet2 thì trừ là dễ hiểu nhất chứ làm như bạn rất khó bảo trì code.
 
1/ Nếu chứng từ nào bằng nhau giữa 2 sheet thì không kê ra ở sheet so sánh? Đúng lý ra phải kê lên hết dù hiệu số = 0
2/ Tại sao ở sheet2, chứng từ không có đuôi /GNT?
1. Vì để sheet3 giảm tải dung lượng và loại bỏ các chứng từ đã khớp nên sau khi lọc autofilter mình đã bỏ dòng khớp (chênh lệch bằng 0)
2. Sheet1 là bảng kê đã nhập nên phần mềm tự sinh ra đuôi để phân biệt nhập vào khu vực nào, còn sheet2 không có đuôi vì nó là chứng từ nhân về để cập nhật vào sheet1, sẽ có lúc điều chỉnh,... làm sai lệch 2 sheet
 
Góp vui, bạn dùng thử trong khi chờ các giải pháp khác.
Hãy nhấn nút SO SANH ở sh3 và xem kết quả
Mã:
Sub SoSanh()
Dim i&, j&, k&, Lr1&, Lr2&, n&, m&
Dim Arr1(), Arr2(), KQ(), KETQUA()
Dim Dic As Object
With Sheet1
Lr1 = .Cells(Rows.Count, 1).End(xlUp).Row
Arr1 = .Range("A2:C" & Lr1).Value
R1 = UBound(Arr1)
End With
With Sheet2
Lr2 = .Cells(Rows.Count, 1).End(xlUp).Row
Arr2 = .Range("A2:C" & Lr2).Value
R2 = UBound(Arr2)
End With
ReDim KQ(1 To R1 + R2, 1 To 5)
Set Dic = CreateObject("scripting.dictionary")

For i = 1 To R1
    Keys = Application.Substitute(Trim(Arr1(i, 1)), "/GNT", "")
    If Not Dic.Exists(Keys) Then
        t = t + 1
        Dic.Add (Keys), t
        KQ(t, 1) = Format(Keys, "0000#")
        KQ(t, 2) = Arr1(i, 2)
        KQ(t, 3) = Arr1(i, 3)
    Else
        k = Dic.Item(Keys)
        KQ(k, 2) = Arr1(i, 2)
        KQ(k, 3) = KQ(k, 3) + Arr1(i, 3)
    End If
        KQ(t, 5) = KQ(t, 3) - KQ(t, 4)
Next i
For j = 1 To R2
    Temp = Trim(Arr2(j, 1))
    If Not Dic.Exists(Temp) Then
        t = t + 1
        KQ(t, 1) = Format(Temp, "0000#")
        KQ(t, 2) = Arr2(j, 2)
        KQ(t, 4) = Arr2(j, 3)
    Else
        k = Dic.Item(Temp)
        KQ(k, 2) = Arr2(j, 2)
        KQ(k, 4) = KQ(k, 4) + Arr2(j, 3)
        KQ(k, 5) = KQ(k, 3) - KQ(k, 4)
    End If
        KQ(t, 5) = KQ(t, 3) - KQ(t, 4)
Next j
ReDim KETQUA(1 To t, 1 To 5)
For n = 1 To t
    If KQ(n, 3) <> KQ(n, 4) Then
        Z = Z + 1
        For m = 1 To 5
            KETQUA(Z, m) = KQ(n, m)
        Next m
            KETQUA(Z, 1) = Format(KETQUA(Z, 1), "0000#")
    End If
Next n
If Z Then
Sheet3.Cells(2, 1).Resize(Z + 5, 5).ClearContents
Sheet3.Cells(2, 1).Resize(Z, 5) = KETQUA
End If
Set Dic = Nothing
MsgBox " Xong"
End Sub
anh chị em có ghé xem xin góp ý để code được ngắn gọn và xử lý được hết các trường hợp xảy ra. Trân trọng.
Cảm ơn bạn, để mình tải về chạy thử
Bài đã được tự động gộp:

Tôi đề nghị vẫn phải kê các chứng từ khớp số liệu vì có như thế dữ liệu của cột Tổng sheet1 và Tổng sheet2 mới toàn vẹn và ta cũng biết được chứng từ nào khớp.
Rich (BB code):
Sub SS2Sheet()
Dim arrS1, arrS2, arrRsl, Dic As Object
Dim i&, k&, dKey$

    arrS1 = Sheet1.Range("A2:C" & Sheet1.Range("A" & Rows.Count).End(xlUp).Row)
    arrS2 = Sheet2.Range("A2:C" & Sheet2.Range("A" & Rows.Count).End(xlUp).Row)
    Set Dic = CreateObject("Scripting.Dictionary")
    ReDim arrRsl(1 To UBound(arrS1) + UBound(arrS2), 1 To 5)
    For i = 1 To UBound(arrS1)
        dKey = arrS1(i, 1)
        If Not Dic.Exists(dKey) Then
            k = k + 1
            Dic.Add dKey, k
            arrRsl(k, 1) = dKey
            arrRsl(k, 2) = arrS1(i, 2)
            arrRsl(k, 3) = arrS1(i, 3)
            arrRsl(k, 4) = 0
            arrRsl(k, 5) = arrS1(i, 3)
        Else
            arrRsl(Dic.Item(dKey), 3) = arrRsl(Dic.Item(dKey), 3) + arrS1(i, 3)
            arrRsl(Dic.Item(dKey), 5) = arrRsl(Dic.Item(dKey), 5) + arrS1(i, 3)
        End If
    Next
    For i = 1 To UBound(arrS2)
        dKey = arrS2(i, 1) & "/GNT"
        If Not Dic.Exists(dKey) Then
            k = k + 1
            Dic.Add dKey, k
            arrRsl(k, 1) = dKey
            arrRsl(k, 2) = arrS2(i, 2)
            arrRsl(k, 3) = 0
            arrRsl(k, 4) = arrS2(i, 3)
            arrRsl(k, 5) = -arrS2(i, 3)
        Else
            arrRsl(Dic.Item(dKey), 4) = arrRsl(Dic.Item(dKey), 4) + arrS2(i, 3)
            arrRsl(Dic.Item(dKey), 5) = arrRsl(Dic.Item(dKey), 5) - arrS2(i, 3)
        End If
    Next
    Sheet3.Range("A2").Resize(UBound(arrS1) + UBound(arrS2), 5).ClearContents
    Sheet3.Range("A2").Resize(k, 5) = arrRsl
    Set Dic = Nothing
End Sub

@HUONGHCKT: Ở cột 5 mảng kết quả, nếu là dữ liệu sheet1 thì cộng, sheet2 thì trừ là dễ hiểu nhất chứ làm như bạn rất khó bảo trì code.
Vì số liệu tháng lên nhiều dòng, khi chạy cả năm sẽ làm tăng dữ liệu rất nhiều, nên mình mong muốn giảm bớt các dòng đã khớp để giảm dung lượng và tăng hiệu quả xử lý dữ liệu. Thanks bạn nhiều
 
Cảm ơn bạn, để mình tải về chạy thử
Bài đã được tự động gộp:


Vì số liệu tháng lên nhiều dòng, khi chạy cả năm sẽ làm tăng dữ liệu rất nhiều, nên mình mong muốn giảm bớt các dòng đã khớp để giảm dung lượng và tăng hiệu quả xử lý dữ liệu. Thanks bạn nhiều
Vậy thì thêm vài dòng lệnh và sửa chút:
Rich (BB code):
Sub SS2Sheet()
Dim arrS1, arrS2, arrRsl, Dic As Object
Dim i&, k&, j&, d&, dKey$

    arrS1 = Sheet1.Range("A2:C" & Sheet1.Range("A" & Rows.Count).End(xlUp).Row)
    arrS2 = Sheet2.Range("A2:C" & Sheet2.Range("A" & Rows.Count).End(xlUp).Row)
    Set Dic = CreateObject("Scripting.Dictionary")
    ReDim arrRsl(1 To UBound(arrS1) + UBound(arrS2), 1 To 5)
    For i = 1 To UBound(arrS1)
        dKey = arrS1(i, 1)
        If Not Dic.Exists(dKey) Then
            k = k + 1
            Dic.Add dKey, k
            arrRsl(k, 1) = dKey
            arrRsl(k, 2) = arrS1(i, 2)
            arrRsl(k, 3) = arrS1(i, 3)
            arrRsl(k, 4) = 0
            arrRsl(k, 5) = arrS1(i, 3)
        Else
            arrRsl(Dic.Item(dKey), 3) = arrRsl(Dic.Item(dKey), 3) + arrS1(i, 3)
            arrRsl(Dic.Item(dKey), 5) = arrRsl(Dic.Item(dKey), 5) + arrS1(i, 3)
        End If
    Next
    For i = 1 To UBound(arrS2)
        dKey = arrS2(i, 1) & "/GNT"
        If Not Dic.Exists(dKey) Then
            k = k + 1
            Dic.Add dKey, k
            arrRsl(k, 1) = dKey
            arrRsl(k, 2) = arrS2(i, 2)
            arrRsl(k, 3) = 0
            arrRsl(k, 4) = arrS2(i, 3)
            arrRsl(k, 5) = -arrS2(i, 3)
        Else
            arrRsl(Dic.Item(dKey), 4) = arrRsl(Dic.Item(dKey), 4) + arrS2(i, 3)
            arrRsl(Dic.Item(dKey), 5) = arrRsl(Dic.Item(dKey), 5) - arrS2(i, 3)
        End If
    Next
'Xóa dòng khớp sheet1 và sheet2
    For i = 1 To k
        If arrRsl(i, 5) <> 0 Then
            d = d + 1
            For j = 1 To UBound(arrRsl, 2)
                arrRsl(d, j) = arrRsl(i, j)
            Next
        End If
    Next
    Sheet3.Range("A2").Resize(UBound(arrS1) + UBound(arrS2), 5).ClearContents
    Sheet3.Range("A2").Resize(d, 5) = arrRsl
    Set Dic = Nothing
End Sub
 
Vậy thì thêm vài dòng lệnh và sửa chút:
Rich (BB code):
Sub SS2Sheet()
Dim arrS1, arrS2, arrRsl, Dic As Object
Dim i&, k&, j&, d&, dKey$

    arrS1 = Sheet1.Range("A2:C" & Sheet1.Range("A" & Rows.Count).End(xlUp).Row)
    arrS2 = Sheet2.Range("A2:C" & Sheet2.Range("A" & Rows.Count).End(xlUp).Row)
    Set Dic = CreateObject("Scripting.Dictionary")
    ReDim arrRsl(1 To UBound(arrS1) + UBound(arrS2), 1 To 5)
    For i = 1 To UBound(arrS1)
        dKey = arrS1(i, 1)
        If Not Dic.Exists(dKey) Then
            k = k + 1
            Dic.Add dKey, k
            arrRsl(k, 1) = dKey
            arrRsl(k, 2) = arrS1(i, 2)
            arrRsl(k, 3) = arrS1(i, 3)
            arrRsl(k, 4) = 0
            arrRsl(k, 5) = arrS1(i, 3)
        Else
            arrRsl(Dic.Item(dKey), 3) = arrRsl(Dic.Item(dKey), 3) + arrS1(i, 3)
            arrRsl(Dic.Item(dKey), 5) = arrRsl(Dic.Item(dKey), 5) + arrS1(i, 3)
        End If
    Next
    For i = 1 To UBound(arrS2)
        dKey = arrS2(i, 1) & "/GNT"
        If Not Dic.Exists(dKey) Then
            k = k + 1
            Dic.Add dKey, k
            arrRsl(k, 1) = dKey
            arrRsl(k, 2) = arrS2(i, 2)
            arrRsl(k, 3) = 0
            arrRsl(k, 4) = arrS2(i, 3)
            arrRsl(k, 5) = -arrS2(i, 3)
        Else
            arrRsl(Dic.Item(dKey), 4) = arrRsl(Dic.Item(dKey), 4) + arrS2(i, 3)
            arrRsl(Dic.Item(dKey), 5) = arrRsl(Dic.Item(dKey), 5) - arrS2(i, 3)
        End If
    Next
'Xóa dòng khớp sheet1 và sheet2
    For i = 1 To k
        If arrRsl(i, 5) <> 0 Then
            d = d + 1
            For j = 1 To UBound(arrRsl, 2)
                arrRsl(d, j) = arrRsl(i, j)
            Next
        End If
    Next
    Sheet3.Range("A2").Resize(UBound(arrS1) + UBound(arrS2), 5).ClearContents
    Sheet3.Range("A2").Resize(d, 5) = arrRsl
    Set Dic = Nothing
End Sub
Cảm ơn bạn nhiều, code chạy rất ổn
 
Web KT

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

Back
Top Bottom