Viết macro tự động tách giá trị theo điều kiện và chèn thêm dòng (2 người xem)

Liên hệ QC

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

  • Tôi tuân thủ nội quy khi đăng bài

    NTNtran

    Thành viên mới
    Tham gia
    6/3/23
    Bài viết
    6
    Được thích
    4
    Em có 1 bảng tính vài trăm người và cần xử lý như sau: nếu giá trị tại cột H (cột thứ 8), bắt đầu từ dòng số 5, lớn hơn 500,000,000, thì sẽ tự động tách thành nhiều dòng, mỗi dòng có giá trị 500,000,000, và nếu còn dư thì dòng cuối cùng sẽ chứa phần dư. Các cao nhân giúp em với ạ.
     

    File đính kèm

    Nhờ Copilot giúp đây:
    PHP:
    Function PhanBoTien(SoTien As Double) As Variant
      'Hàm Xài Trong Excel 365   '
        Const DonVi As Double = 500
        ReDim KetQua(1 To 9, 1 To 1) As Double
        Dim SoLan As Integer, Du As Double, i As Integer
    
        SoLan = Int(SoTien / DonVi)
        Du = SoTien Mod DonVi
        ReDim KetQua(0 To SoLan - 1 + IIf(Du > 0, 1, 0), 1 To 1)
    
        For i = 0 To SoLan - 1
            KetQua(i, 1) = DonVi
        Next i
    
        If Du > 0 Then
            KetQua(UBound(KetQua), 1) = Du
        End If
        PhanBoTien = KetQua
    End Function
     
    Nhờ Copilot giúp đây:
    PHP:
    Function PhanBoTien(SoTien As Double) As Variant
      'Hàm Xài Trong Excel 365   '
        Const DonVi As Double = 500
        ReDim KetQua(1 To 9, 1 To 1) As Double
        Dim SoLan As Integer, Du As Double, i As Integer
    
        SoLan = Int(SoTien / DonVi)
        Du = SoTien Mod DonVi
        ReDim KetQua(0 To SoLan - 1 + IIf(Du > 0, 1, 0), 1 To 1)
    
        For i = 0 To SoLan - 1
            KetQua(i, 1) = DonVi
        Next i
    
        If Du > 0 Then
            KetQua(UBound(KetQua), 1) = Du
        End If
        PhanBoTien = KetQua
    End Function
    Cảm ơn bạn đã trợ giúp, nhưng đoạn mã không chạy được ạ. Nhưng nhờ có bạn mà mình đã tìm được cách xử lý rồi ạ.
    Bài đã được tự động gộp:

    Bạn dùng thử xem thế nào.
    Cảm ơn anh đã trợ giúp. Nhưng khi em chạy thử thì không ra được kết quả như em mong muốn ạ. Em đã tìm được cách xử lý vấn đề nhờ những gợi ý từ các anh ạ. Em cảm ơn rất nhiều ạ.
     
    Cảm ơn bạn đã giúp đỡ, nhưng đoạn mã không chạy được. Nhưng nhờ có bạn mà mình đã tìm được cách xử lý rồi ạ.
    [tự động hợp nhất]1759504487[/tự động hợp nhất]

    Cảm ơn anh đã giúp đỡ. Nhưng khi em thử thì không ra kết quả như em mong muốn ạ. Em đã tìm được cách xử lý vấn đề nhờ những lời khuyên từ các anh ạ. Em cảm ơn rất nhiều ạ.
    Nếu vậy, bạn phải đưa ra kết quả mong muốn như thế nào để mọi người có thể hiểu được.
     
    Nếu có thể thì chia sẻ cách sử lý đó lên để bạn nào có trường hợp tương tự cũng áp dụng được.
    Đây là đoạn mã mình đã dùng để chạy. Nó tách xong và ghi vào sheet mới, giá trị sau khi tách sẽ được ghi vào cột thứ 9, đồng thời nội dung các ô còn lại của dòng gốc cũng được tự điền luôn. Hy vong sẽ giúp được cho bạn nào gặp trường hợp tương tự ạ.

    Function PhanBoTien(SoTien As Double) As Variant
    Const DonVi As Double = 500000000
    Dim ketQua() As Double
    Dim SoLan As Long, Du As Double, i As Long

    If SoTien <= 0 Then
    PhanBoTien = Array()
    Exit Function
    End If

    SoLan = WorksheetFunction.RoundDown(SoTien / DonVi, 0)
    Du = SoTien - (SoLan * DonVi)

    ReDim ketQua(0 To SoLan - 1 + IIf(Du > 0, 1, 0))

    For i = 0 To SoLan - 1
    ketQua(i) = DonVi
    Next i

    If Du > 0 Then
    ketQua(UBound(ketQua)) = Du
    End If

    PhanBoTien = ketQua
    End Function

    Sub TachBangTinh_SangSheetMoi()
    Dim wsNguon As Worksheet, wsMoi As Worksheet
    Dim i As Long, dongMoi As Long, lastRow As Long, lastCol As Long
    Dim val As Double, ketQua As Variant
    Dim originalRow As Range, j As Long

    Set wsNguon = ActiveSheet
    Set wsMoi = Worksheets.Add(After:=Worksheets(Worksheets.Count))
    wsMoi.Name = "DaTach_" & Format(Now, "hhmmss")

    lastCol = wsNguon.Cells(5, wsNguon.Columns.Count).End(xlToLeft).Column
    wsNguon.Range(wsNguon.Cells(5, 1), wsNguon.Cells(5, lastCol)).Copy
    wsMoi.Range("A1").PasteSpecial xlPasteValues

    lastRow = wsNguon.Cells(wsNguon.Rows.Count, "A").End(xlUp).Row
    dongMoi = 2

    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False

    For i = 6 To lastRow
    If IsNumeric(wsNguon.Cells(i, 8).Value) Then
    val = wsNguon.Cells(i, 8).Value
    If val > 0 Then
    ketQua = PhanBoTien(val)
    Set originalRow = wsNguon.Range(wsNguon.Cells(i, 1), wsNguon.Cells(i, lastCol))

    For j = LBound(ketQua) To UBound(ketQua)
    originalRow.Copy
    wsMoi.Range(wsMoi.Cells(dongMoi, 1), wsMoi.Cells(dongMoi, lastCol)).PasteSpecial xlPasteValues
    wsMoi.Cells(dongMoi, 9).Value = ketQua(j) ' Ghi và o cột thứ 9
    dongMoi = dongMoi + 1
    Next j
    End If
    End If
    Next i

    Application.CutCopyMode = False
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True

    MsgBox "Äã tách xong và ghi và o sheet má»›i: " & wsMoi.Name, vbInformation
    End Sub
    Bài đã được tự động gộp:

    Nếu vậy, bạn phải đưa ra kết quả mong muốn như thế nào để mọi người có thể hiểu được.
    Vâng. Do em chưa đưa ra rõ kết quả mong muốn nên mọi người chưa hiểu để có thể giúp em 1 cách sát nhất. Cảm ơn lời góp ý của anh ạ. Lần sau em sẽ lưu ý hơn ạ.
     

    File đính kèm

    Em có 1 bảng tính vài trăm người và cần xử lý như sau: nếu giá trị tại cột H (cột thứ 8), bắt đầu từ dòng số 5, lớn hơn 500,000,000, thì sẽ tự động tách thành nhiều dòng, mỗi dòng có giá trị 500,000,000, và nếu còn dư thì dòng cuối cùng sẽ chứa phần dư. Các cao nhân giúp em với ạ.
    Dùng thử code sau . . .
    Mã:
    Sub abc()
      Dim sh As Worksheet, arr(), res()
      Dim sR&, i&, j&, k&, n&, T#
      Const C# = 500000000
     
      With Sheets("131 TK 6666")
        arr = .Range("A5", .Range("H" & Rows.Count).End(xlUp)).Value
      End With
      sR = UBound(arr)
     
    KhaiBaoLaiTangSoDongKetQua:
      n = n + 10000 'Neu du lieu nhieu co the tang So 10000 len
      k = 0
      ReDim res(1 To n, 1 To 9) 'Tao mang ket qua
      For i = 1 To sR
        T = arr(i, 8)
        Do While T > 0
          k = k + 1
          If k > n Then GoTo KhaiBaoLaiTangSoDongKetQua
          For j = 1 To 8
            res(k, j) = arr(i, j)
          Next j
          If T > C Then res(k, 9) = C Else res(k, 9) = T
          T = T - res(k, 9)
        Loop
      Next i
      Set sh = Worksheets.Add(After:=Worksheets(Worksheets.Count))
      sh.Name = "DaTach_" & Format(Now, "ddhhmmss")
      sh.Range("A5").Resize(k, 9) = res
      MsgBox "Da tach xong va ghi vao sheet: " & Chr(10) & Chr(10) & sh.Name, vbInformation
    End Sub
    Code đã chỉnh lại để xử lý dữ liệu khá lớn
     
    Lần chỉnh sửa cuối:
    Dùng thử code sau . . .
    Mã:
    Sub abc()
      Dim sh As Worksheet, arr(), res()
      Dim sR&, i&, j&, k&, n&
      Const C# = 500000000
     
      With Sheets("131 TK 6666")
        arr = .Range("A5", .Range("H" & Rows.Count).End(xlUp)).Value
      End With
      sR = UBound(arr)
     
    KhaiBaoLaiTangSoDongKetQua:
      n = n + 10000 'Neu du lieu nhieu co the tang So 10000 len
      ReDim res(1 To n, 1 To 9) 'Tao mang ket qua
      For i = 1 To sR
        Do While arr(i, 8) > 0
          k = k + 1
          If k > n Then GoTo KhaiBaoLaiTangSoDongKetQua
          For j = 1 To 8
            res(k, j) = arr(i, j)
          Next j
          If arr(i, 8) > C Then res(k, 9) = C Else res(k, 9) = arr(i, 8)
          arr(i, 8) = arr(i, 8) - res(k, 9)
        Loop
      Next i
      Set sh = Worksheets.Add(After:=Worksheets(Worksheets.Count))
      sh.Name = "DaTach_" & Format(Now, "ddhhmmss")
      sh.Range("A5").Resize(k, 9) = res
      MsgBox "Da tach xong va ghi vao sheet: " & Chr(10) & Chr(10) & sh.Name, vbInformation
    End Sub
    Em cảm ơn anh rất nhiều ạ. Đây thực sự là đoạn mã mà em cần (Dù em đã xử lý được vấn đề rồi).
     
    Em cảm ơn anh rất nhiều ạ. Đây thực sự là đoạn mã mà em cần (Dù em đã xử lý được vấn đề rồi).
    Bạn chưa xử lý dòng cuối. Phần "tổng cộng" vẫn phân bổ.
    Đoạn For i = 1 To sR bạn sửa lại thành For i = 1 To sR - 1 thì sẽ bỏ dòng tổng tiền (mà hình như tổng tiền trong sheet gốc của bạn bị tổng sai)
    Code của bác HIEUCD thì quá hay và cao cấp rồi.
     
    PHP:
    Sub TaiPhanBo()
     Const FB As LongLong = 500000000
     Dim Rws As Long, DCK As LongLong, SoDu As LongLong, W As Long, SoDg As Integer, Col As Integer
     Dim Dg As Integer                          'DCK:= Du Cuôi Kì  '
     Dim Cls As Range
     
     Sheets("131TK").Select
     Rws = Sheets("131TK").UsedRange.Rows.Count
     SoFB = Cells(Rws + 9, "H").End(xlUp).Value / FB + Rws
     ReDim Arr(1 To SoFB, 1 To 4)
     For Each Cls In Range([A5], [A5].End(xlDown))
        W = W + 1:                          '    If W > 7 Then Exit For '
        DCK = Cells(Cls.Row, "H").Value:        SoDg = Int(DCK / FB)
        SoDu = DCK - SoDg * FB
        If SoDg < 1 Then
            Arr(W, 1) = Cls.Value:              Arr(W, 2) = Cls.Offset(, 1).Value
            Dg = Cls.Row:                       Arr(W, 3) = Cells(Dg, "F").Value
            Arr(W, 4) = DCK
        Else
            Arr(W, 1) = Cls.Value:              Arr(W, 2) = Cls.Offset(, 1).Value
            Dg = Cls.Row:                       Arr(W, 3) = Cells(Dg, "F").Value
            For hg = 1 To SoDg
                Arr(W, 4) = FB:                 W = W + 1
            Next hg
            If SoDu > 0 Then
                Arr(W, 4) = SoDu
            Else
                W = W - 1
            End If
        End If
     Next Cls
     [K5].Resize(W, 4).Value = Arr()
    End Sub
     
    Bạn chưa xử lý dòng cuối. Phần "tổng cộng" vẫn phân bổ.
    Đoạn For i = 1 To sR bạn sửa lại thành For i = 1 To sR - 1 thì sẽ bỏ dòng tổng tiền (mà hình như tổng tiền trong sheet gốc của bạn bị tổng sai)
    Code của bác HIEUCD thì quá hay và cao cấp rồi.
    Dạ. Em cảm ơn anh nhiều ạ. Em đã khắc phục theo hướng dẫn của anh ạ. Cảm ơn anh rất nhiều.
     
    PHP:
    Sub TaiPhanBo()
     Const FB As LongLong = 500000000
     Dim Rws As Long, DCK As LongLong, SoDu As LongLong, W As Long, SoDg As Integer, Col As Integer
     Dim Dg As Integer                          'DCK:= Du Cuôi Kì  '
     Dim Cls As Range
     
     Sheets("131TK").Select
     Rws = Sheets("131TK").UsedRange.Rows.Count
     SoFB = Cells(Rws + 9, "H").End(xlUp).Value / FB + Rws
     ReDim Arr(1 To SoFB, 1 To 4)
     For Each Cls In Range([A5], [A5].End(xlDown))
        W = W + 1:                          '    If W > 7 Then Exit For '
        DCK = Cells(Cls.Row, "H").Value:        SoDg = Int(DCK / FB)
        SoDu = DCK - SoDg * FB
        If SoDg < 1 Then
            Arr(W, 1) = Cls.Value:              Arr(W, 2) = Cls.Offset(, 1).Value
            Dg = Cls.Row:                       Arr(W, 3) = Cells(Dg, "F").Value
            Arr(W, 4) = DCK
        Else
            Arr(W, 1) = Cls.Value:              Arr(W, 2) = Cls.Offset(, 1).Value
            Dg = Cls.Row:                       Arr(W, 3) = Cells(Dg, "F").Value
            For hg = 1 To SoDg
                Arr(W, 4) = FB:                 W = W + 1
            Next hg
            If SoDu > 0 Then
                Arr(W, 4) = SoDu
            Else
                W = W - 1
            End If
        End If
     Next Cls
     [K5].Resize(W, 4).Value = Arr()
    End Sub
    Dạ. Em cảm ơn anh nhiều ạ. Nhưng code em chạy bị lỗi, không chạy được anh ơi.
     
    Dạ. Em cảm ơn anh nhiều ạ. Nhưng code em chạy bị lỗi, không chạy được anh ơi.
    Code chỉ là giới thiệu sơ bộ thêm 1 cách làm so với vài ba bài giải đáp trước đó đúng & trúng rồi!
    & vì là sơ bộ nên hoàn toàn không đúng ý tác giả bài đăng & chỉ nêu cái sườn để thấy toàn cảnh thêm 1 cách làm thôi!
    Mong tác giả & mọi người chỉ coi là bài tham khảo lúc rỗi!

    Thân ái & vui vẻ!
     

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

    Back
    Top Bottom