Code vba tách dữ liệu ra thành từng sheet riêng. (1 người xem)

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

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

nhk007dn

Thành viên chính thức
Tham gia
12/11/12
Bài viết
74
Được thích
7
Chào các bạn trên GPE!
Dựa vào code tách dữ liệu ra thành các sheet mình vừa tìm được trên GPE, mình chỉnh sửa theo yêu cầu và đến giai đoạn paste thì gặp lỗi. Mong các bạn biết giúp mình khắc phục lỗi để hoàn chỉnh đoạn code với.
Đoạn code mình có đặt ở file đính kèm.
Mình cảm ơn!
 

File đính kèm

Chào các bạn trên GPE!
Dựa vào code tách dữ liệu ra thành các sheet mình vừa tìm được trên GPE, mình chỉnh sửa theo yêu cầu và đến giai đoạn paste thì gặp lỗi. Mong các bạn biết giúp mình khắc phục lỗi để hoàn chỉnh đoạn code với.
Đoạn code mình có đặt ở file đính kèm.
Mình cảm ơn!
Code người ta sheet dữ liệu tổng có tên là "dataloc" của bạn tên khác sao nó không báo lỗi???? Chưa kể tới lệnh AutoFilter cũng bị sai luôn nữa!
 
Upvote 0
Code người ta sheet dữ liệu tổng có tên là "dataloc" của bạn tên khác sao nó không báo lỗi???? Chưa kể tới lệnh AutoFilter cũng bị sai luôn nữa!

file gốc mình tìm được trên GPE có sheet dữ liệu tên "tong hop" bạn ah?
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Bạn nào biết giúp mình vấn đề này với.
Mình cảm ơn.
 
Upvote 0
File của bạn sao có tý dữ liệu vậy? Bạn gửi lại File có nhiều dữ liệu 1 chút, đưa kết quả vài sheet sau khi tách nữa để tôi tiện đối chiếu kết quả!

Mình nghĩ ít dữ liệu sẽ nhanh hơn. bạn thông cảm nha.
Mình cảm ơn!
 

File đính kèm

Upvote 0
THử cách 'Mảng trong mảng' này xem sao
Mã:
Sub TachDL_GPE()
Dim Endr As Long, Dic As Object, i As Long, Arr(), j As Long
Dim DL(), KQ(), r As Long, k As Long
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual

With Sheet10
    .AutoFilterMode = False
    Endr = .Range("B65500").End(xlUp).Row
    If Endr > 11 Then
        Set Dic = CreateObject("scripting.dictionary")
        DL = .Range("B12:E" & Endr)
        ReDim KQ(1 To Endr - 11, 1 To 3)
        ReDim Arr(1 To Endr - 11, 1 To 4)
        For i = 1 To Endr - 11
            If Not Dic.Exists(DL(i, 1)) Then
                j = j + 1
                Dic.Add DL(i, 1), j
                KQ(j, 1) = 1
                KQ(j, 3) = DL(i, 1)
                KQ(j, 2) = Arr
                KQ(j, 2)(1, 1) = DL(i, 1)
                KQ(j, 2)(1, 2) = DL(i, 2)
                KQ(j, 2)(1, 3) = DL(i, 3)
                KQ(j, 2)(1, 4) = DL(i, 4)
            Else
                r = Dic.Item(DL(i, 1))
                k = KQ(r, 1) + 1
                KQ(r, 1) = k
                KQ(r, 2)(k, 1) = DL(i, 1)
                KQ(r, 2)(k, 2) = DL(i, 2)
                KQ(r, 2)(k, 3) = DL(i, 3)
                KQ(r, 2)(k, 4) = DL(i, 4)
            End If
        Next i
        For i = 1 To j
            Sheets("BangMau").Copy after:=Sheets(Sheets.Count)
            With ActiveSheet
               .Name = KQ(i, 3)
               .Range("B12").Resize(KQ(i, 1), 4).Value = KQ(i, 2)
            End With
        Next i
    End If
End With
Set Dic= Nothing
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
 
Upvote 0
THử cách 'Mảng trong mảng' này xem sao
Mã:
Sub TachDL_GPE()
Dim Endr As Long, Dic As Object, i As Long, Arr(), j As Long
Dim DL(), KQ(), r As Long, k As Long
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual

With Sheet10
    .AutoFilterMode = False
    Endr = .Range("B65500").End(xlUp).Row
    If Endr > 11 Then
        Set Dic = CreateObject("scripting.dictionary")
        DL = .Range("B12:E" & Endr)
        ReDim KQ(1 To Endr - 11, 1 To 3)
        ReDim Arr(1 To Endr - 11, 1 To 4)
        For i = 1 To Endr - 11
            If Not Dic.Exists(DL(i, 1)) Then
                j = j + 1
                Dic.Add DL(i, 1), j
                KQ(j, 1) = 1
                KQ(j, 3) = DL(i, 1)
                KQ(j, 2) = Arr
                KQ(j, 2)(1, 1) = DL(i, 1)
                KQ(j, 2)(1, 2) = DL(i, 2)
                KQ(j, 2)(1, 3) = DL(i, 3)
                KQ(j, 2)(1, 4) = DL(i, 4)
            Else
                r = Dic.Item(DL(i, 1))
                k = KQ(r, 1) + 1
                KQ(r, 1) = k
                KQ(r, 2)(k, 1) = DL(i, 1)
                KQ(r, 2)(k, 2) = DL(i, 2)
                KQ(r, 2)(k, 3) = DL(i, 3)
                KQ(r, 2)(k, 4) = DL(i, 4)
            End If
        Next i
        For i = 1 To j
            Sheets("BangMau").Copy after:=Sheets(Sheets.Count)
            With ActiveSheet
               .Name = KQ(i, 3)
               .Range("B12").Resize(KQ(i, 1), 4).Value = KQ(i, 2)
            End With
        Next i
    End If
End With
Set Dic= Nothing
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub

Bạn có thể giúp mình thêm chút nữa là khi chạy code các lần sau (lần 2, lần 3) thì các sheet đã tạo trước đó (18, 16, 22, 25,...) sẽ tự xóa đi và tạo lại các sheet khác. Vì bây giờ nếu chạy code lại các lần sau thì bị báo lỗi.
và cho thêm cột số thứ tự ở các sheet tạo ra nữa.
Còn kết quả thì đúng như ý mình rồi, Mình cảm ơn bạn!
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn có thể giúp mình thêm chút nữa là khi chạy code các lần sau (lần 2, lần 3) thì các sheet đã tạo trước đó (18, 16, 22, 25,...) sẽ tự xóa đi và tạo lại các sheet khác. Vì bây giờ nếu chạy code lại các lần sau thì bị báo lỗi.
và cho thêm cột số thứ tự ở các sheet tạo ra nữa.
Còn kết quả thì đúng như ý mình rồi, Mình cảm ơn bạn!
Code của tôi chạy sẽ không báo lỗi nếu Sheet tạo sau bị trùng! Tôi đính kèm lại File ở bài #7 rồi đó. File trước tôi nhầm lẫn chút xíu!
 
Upvote 0
Bạn muốn tách theo mã cột B hay cột C vậy? Bạn ko nõi rõ nên tôi chọn bừa!
 
Upvote 0
Thử lại xem nhé !
Mã:
Sub TachDL_GPE()
Dim Endr As Long, Dic As Object, i As Long, Arr(), j As Long
Dim DL(), KQ(), r As Long, k As Long, Sh As Worksheet
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual

'Xoa cac sheet da tao truoc do - chi giu lai sheet So- Lieu va sheet BangMau
Application.DisplayAlerts = False
For Each Sh In ThisWorkbook.Sheets
    If Sh.Name <> "So-Lieu" And Sh.Name <> "BangMau" Then
        Sh.Delete
    End If
Next
Application.DisplayAlerts = True

With Sheet10
    .AutoFilterMode = False
    Endr = .Range("B65500").End(xlUp).Row
    If Endr > 11 Then
        Set Dic = CreateObject("scripting.dictionary")
        DL = .Range("B12:E" & Endr)
        ReDim KQ(1 To Endr - 11, 1 To 3)
        ReDim Arr(1 To Endr - 11, 1 To 5)
        For i = 1 To Endr - 11
            If Not Dic.Exists(DL(i, 1)) Then
                j = j + 1
                Dic.Add DL(i, 1), j
                KQ(j, 1) = 1
                KQ(j, 3) = DL(i, 1)
                KQ(j, 2) = Arr
                KQ(j, 2)(1, 1) = 1
                KQ(j, 2)(1, 2) = DL(i, 1)
                KQ(j, 2)(1, 3) = DL(i, 2)
                KQ(j, 2)(1, 4) = DL(i, 3)
                KQ(j, 2)(1, 5) = DL(i, 4)
            Else
                r = Dic.Item(DL(i, 1))
                k = KQ(r, 1) + 1
                KQ(r, 1) = k
                KQ(r, 2)(k, 1) = k
                KQ(r, 2)(k, 2) = DL(i, 1)
                KQ(r, 2)(k, 3) = DL(i, 2)
                KQ(r, 2)(k, 4) = DL(i, 3)
                KQ(r, 2)(k, 5) = DL(i, 4)
            End If
        Next i
        For i = 1 To j
            Sheets("BangMau").Copy after:=Sheets(Sheets.Count)
            With ActiveSheet
               .Name = KQ(i, 3)
               .Range("A12").Resize(KQ(i, 1), 5).Value = KQ(i, 2)
            End With
        Next i
    Else
        MsgBox "Co du lieu dau ma lam  - hehe !", , GPE
    End If
End With
Set Dic = Nothing
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub

P/s: đừng nói mình kẻ thêm Border nữa nha !
 
Lần chỉnh sửa cuối:
Upvote 0
Thử lại xem nhé !

P/s: đừng nói mình kẻ thêm Border nữa nha !

hihi. sao thời gian mày mò học hỏi trên GPE thì mình cũng kẻ được sơ sơ rồi. Phần này ko quan trọng lắm nên để mình tự mò cũng được. Phần quan trọng nhất bạn đã giúp rồi. Mình cảm ơn!
 
Upvote 0
Bài này chỉ cần sửa lại tiêu đề cột một chút, cụ thể là bỏ merge cell, ta sẽ có thể dùng Advanced Filter trích một cách dễ dàng
Cũng theo như tôi nói ở trên thì ta có thể xử lý code chỉ với 1 vòng lập
 
Upvote 0
Bài này chỉ cần sửa lại tiêu đề cột một chút, cụ thể là bỏ merge cell, ta sẽ có thể dùng Advanced Filter trích một cách dễ dàng
Cũng theo như tôi nói ở trên thì ta có thể xử lý code chỉ với 1 vòng lập

anh ndu96081631 có thể xử lý theo cách của anh cho em đoạn code mẫu được không?
em cảm ơn anh trước!
 
Upvote 0
anh ndu96081631 có thể xử lý theo cách của anh cho em đoạn code mẫu được không?
em cảm ơn anh trước!
Bạn thấy code của quocphuong88 dùng được rồi thôi. Đây là gợi ý của thầy ndu cho các thành viên luyện cách tối ưu code mà. Bạn thử sức xem sao?
 
Upvote 0
Bạn thấy code của quocphuong88 dùng được rồi thôi. Đây là gợi ý của thầy ndu cho các thành viên luyện cách tối ưu code mà. Bạn thử sức xem sao?

Mình cảm ơn bạn góp ý, mình chưa biết gì nhưng vì nghe anh ndu nói hình dung chắc code ngắn gọn nên mới mạo muội thôi để biết thêm thôi.
ah, khi mình chuyển code của bạn quocphuong88 thành add-in để sử dụng thì gặp lỗi type mismatch gì đó, không biết lỗi này là do đâu, vì khi sử dụng bình thường trên file .xlsm thì không bị lỗi.
Bạn nào biết giúp mình với.


Mình cảm ơn!
 

File đính kèm

Upvote 0
anh ndu96081631 có thể xử lý theo cách của anh cho em đoạn code mẫu được không?
em cảm ơn anh trước!

Nó thế này:
Mã:
Sub Main()
  Dim dic As Object
  Dim wks As Worksheet
  Dim aItems, item
  Dim tmp As String
  Application.DisplayAlerts = False
  Application.ScreenUpdating = False
  Set dic = CreateObject("Scripting.Dictionary")
  Set wks = Worksheets("So-Lieu")
  With wks
    aItems = .Range("B12:B1000").Value
    .Range("IV1").Value = .Range("B11")
  End With
  For Each item In aItems
    tmp = CStr(item)
    If Len(tmp) Then
      If Not dic.Exists(tmp) Then
        dic.Add tmp, Empty
        If SheetExists(tmp) Then Worksheets(tmp).Delete
        wks.Range("IV2").Value = tmp
        With Sheets.Add(After:=Sheets(Sheets.Count))
          .Name = tmp
          wks.Range("B11:F1000").AdvancedFilter 2, wks.Range("IV1:IV2"), .Range("B11")
          wks.Range("C2:E6").Copy .Range("C2")
        End With
      End If
    End If
  Next
  wks.Activate: wks.Range("IV1:IV2").Clear
  Application.DisplayAlerts = True
  Application.ScreenUpdating = True
  MsgBox "Done!"
End Sub
Private Function SheetExists(ByVal SheetName As String) As Boolean
  On Error Resume Next
  SheetExists = Not Sheets(SheetName) Is Nothing
End Function
Nhân tiện tôi cũng xóa luôn mấy cái name và công thức tại khu vực E2:E6
 

File đính kèm

Upvote 0
Nó thế này:

Nhân tiện tôi cũng xóa luôn mấy cái name và công thức tại khu vực E2:E6

cảm ơn anh ndu!
mấy cái name đó là có liên quan đến code của 1 file em tìm trên mạng, code đó dùng để xử lý tiếp phần kết quả mà code của anh ndu, bạn chuot và ban quoc giúp ở topic này. do vậy nếu bỏ name và công thức đó đi thì em sợ code đó không hoạt động.
em up code đó lên để anh và các bạn xem.

Mã:
Option Explicit


Sub CutEm()
    Dim rOut        As Range
    Dim cell        As Range
    Dim avInp       As Variant
    Dim dKerf       As Double
    Dim dStk        As Double
    Dim iOut        As Long
    Dim nOut        As Long


    dKerf = Range("ptrKerf").Value2
    dStk = Range("ptrStk").Value2


    With Range("rgnInp")
        If WorksheetFunction.Max(.Columns(1).Value) > dStk Then
            MsgBox "Piece length cannot exceed stock length", _
                   Buttons:=vbOKOnly, _
                   Title:="shg Cut List"
            Exit Sub
        End If
        avInp = .Value
        iOut = .Column + 3
        Set rOut = .Worksheet.Cells(.Row, iOut).Resize(.Rows.Count)
    End With
    
    ' clear the output area
    rOut.Resize(, Columns.Count - iOut + 1).EntireColumn.Clear
    rOut(1, 0).Resize(Rows.Count - rOut.Row).ClearContents


    ' get the cuts
    Application.ScreenUpdating = False
    With WorksheetFunction
        Do While .Sum(.Index(avInp, 0, 2))
            nOut = nOut + 1
            rOut.Columns(nOut) = .Transpose(aiCut(avInp, dKerf, dStk))
        Loop
    End With


    ' finish up


    Set rOut = rOut.Resize(, nOut)
    With rOut
        .Style = "Input"
        .NumberFormat = "General_);;"
        
        With .Rows(-1)
            .FormulaR1C1 = "=column() - " & .Column - 1
            .Value = .Value
            .Style = "Input"
        End With
        
        With .Rows(0)
            .FormulaR1C1 = "=max(0, ptrStk - sumproduct(r[1]c:r[" & rOut.Rows.Count & "]c, rgnLen + ptrKerf))"
            .Style = "Formula"
            .NumberFormat = "0.0"
        End With
        
        .Columns(0).FormulaR1C1 = "=sum(rc[1]:rc[" & nOut & "])"
        .EntireColumn.AutoFit
        .Worksheet.PageSetup.PrintArea = .Address
    End With
    
    Application.ScreenUpdating = True
    Application.Speech.Speak "Done!"
End Sub


Function aiCut(avInp As Variant, _
               dKerf As Double, _
               dStk As Double) As Long()
    ' shg 2012


    ' 1-based array avInp is records of item {length, qty} to cut,
    ' sorted descending by length


    ' Returns an array containing the number of pieces of each length
    ' to cut from the stock for the least waste, and the qty values of
    ' avInp are reduced accordingly


    Dim col         As Collection   ' working collection of item numbers
    Dim nInp        As Long         ' number of inputs
    Dim iInp        As Long         ' index to avInp
    
    Dim aiQty()     As Long         ' qty of each length cut
    Dim aiMin()     As Long         ' cached current best solution


    Dim dRem        As Double       ' stock length remaining
    Dim dRemMin     As Double       ' smallest remainder so far


    Set col = New Collection
    nInp = UBound(avInp)
    dRemMin = dStk
    ReDim aiQty(1 To nInp)


    With col
        iInp = 1
        dRem = dStk


        Do
            Do While avInp(iInp, 1) > dRem Or avInp(iInp, 2) <= 0
                iInp = iInp + 1
                If iInp > nInp Then
                    If dRem < dRemMin Then
                        ' Debug.Print dRem
                        ' we have a new solution; cache it
                        dRemMin = dRem
                        aiMin = aiQty
                        If dRemMin < 0.001 * dStk Then GoTo Outtahere
                    End If


                    If .Count = 1 Then
                        ' must include the largest, so ...
                        GoTo Outtahere


                    Else
                        iInp = .Item(.Count)
                        If iInp >= nInp Then
                            GoTo Outtahere
                        Else
                            ' remove the last item on the list,
                            ' returning the length and kerf to the stock
                            dRem = dRem + avInp(iInp, 1) + dKerf
                            avInp(iInp, 2) = avInp(iInp, 2) + 1
                            aiQty(iInp) = aiQty(iInp) - 1
                            ' try the next piece instead
                            iInp = iInp + 1
                            .Remove .Count
                        End If
                    End If
                End If
            Loop


            .Add Item:=iInp
            avInp(iInp, 2) = avInp(iInp, 2) - 1
            aiQty(iInp) = aiQty(iInp) + 1
            dRem = dRem - avInp(iInp, 1) - dKerf
        Loop
    End With


Outtahere:
    aiCut = aiMin
    For iInp = 1 To nInp
        avInp(iInp, 2) = avInp(iInp, 2) + aiQty(iInp) - aiMin(iInp)
    Next iInp
End Function
 
Upvote 0
cảm ơn anh ndu!
mấy cái name đó là có liên quan đến code của 1 file em tìm trên mạng, code đó dùng để xử lý tiếp phần kết quả mà code của anh ndu, bạn chuot và ban quoc giúp ở topic này. do vậy nếu bỏ name và công thức đó đi thì em sợ code đó không hoạt động.
em up code đó lên để anh và các bạn xem.

Mấy code gì đó mà bạn sưu tầm tôi không biết đâu (và cũng không có hứng thú tham khảo)
Tôi chỉ làm theo như những gì bạn yêu cầu trong file thôi
(các name tôi có xóa đi nhưng đã sửa lại công thức rồi đấy)
 
Lần chỉnh sửa cuối:
Upvote 0
Mấy code gì đó mà bạn sưu tầm tôi không biết đâu (và cũng không có hứng thứ tham khảo)
Tôi chỉ làm theo như những gì bạn yêu cầu trong file thôi
(các name tôi có xóa đi nhưng đã sửa lại công thức rồi đấy)

Em cảm ơn anh!
phần còn lại để em tự mò mẫm vậy.
Chúc anh cuối tuần vui vẻ!
 
Upvote 0
Em xin nhờ các anh viết thêm cho em vào code #22 để khi tách ra vẫn giữ được định dạng (độ rộng) của các cột như sheet gốc
 
Lần chỉnh sửa cuối:
Upvote 0
Em xin nhờ các anh viết thêm cho em vào code #22 để khi tách ra vẫn giữ được định dạng (độ rộng) của các cột như sheet gốc
Dòng màu đỏ là tôi mới thêm vào!
Mã:
Sub Main()
  Dim dic As Object
  Dim wks As Worksheet
  Dim aItems, item
  Dim tmp As String
  Application.DisplayAlerts = False
  Application.ScreenUpdating = False
  Set dic = CreateObject("Scripting.Dictionary")
  Set wks = Worksheets("So-Lieu")
  With wks
    aItems = .Range("B12:B1000").Value
    .Range("IV1").Value = .Range("B11")
  End With
  For Each item In aItems
    tmp = CStr(item)
    If Len(tmp) Then
      If Not dic.Exists(tmp) Then
        dic.Add tmp, Empty
        If SheetExists(tmp) Then Worksheets(tmp).Delete
        wks.Range("IV2").Value = tmp
        With Sheets.Add(After:=Sheets(Sheets.Count))
          .Name = tmp
          wks.Range("B11:F1000").AdvancedFilter 2, wks.Range("IV1:IV2"), .Range("B11")
          wks.Range("C2:E6").Copy .Range("C2")
       [COLOR=#ff0000]   .columns.AutoFit[/COLOR]
        End With
      End If
    End If
  Next
  wks.Activate: wks.Range("IV1:IV2").Clear
  Application.DisplayAlerts = True
  Application.ScreenUpdating = True
  MsgBox "Done!"
End Sub
Private Function SheetExists(ByVal SheetName As String) As Boolean
  On Error Resume Next
  SheetExists = Not Sheets(SheetName) Is Nothing
End Function
 
Upvote 0
Dòng màu đỏ là tôi mới thêm vào!
Mã:
Sub Main()
  Dim dic As Object
  Dim wks As Worksheet
  Dim aItems, item
  Dim tmp As String
  Application.DisplayAlerts = False
  Application.ScreenUpdating = False
  Set dic = CreateObject("Scripting.Dictionary")
  Set wks = Worksheets("So-Lieu")
  With wks
    aItems = .Range("B12:B1000").Value
    .Range("IV1").Value = .Range("B11")
  End With
  For Each item In aItems
    tmp = CStr(item)
    If Len(tmp) Then
      If Not dic.Exists(tmp) Then
        dic.Add tmp, Empty
        If SheetExists(tmp) Then Worksheets(tmp).Delete
        wks.Range("IV2").Value = tmp
        With Sheets.Add(After:=Sheets(Sheets.Count))
          .Name = tmp
          wks.Range("B11:F1000").AdvancedFilter 2, wks.Range("IV1:IV2"), .Range("B11")
          wks.Range("C2:E6").Copy .Range("C2")
       [COLOR=#ff0000]   .columns.AutoFit[/COLOR]
        End With
      End If
    End If
  Next
  wks.Activate: wks.Range("IV1:IV2").Clear
  Application.DisplayAlerts = True
  Application.ScreenUpdating = True
  MsgBox "Done!"
End Sub
Private Function SheetExists(ByVal SheetName As String) As Boolean
  On Error Resume Next
  SheetExists = Not Sheets(SheetName) Is Nothing
End Function

Tôi e rằng cái chỗ mới thêm vào là: TRẬT LẤT. Bởi người ta yêu cầu:
Em xin nhờ các anh viết thêm cho em vào code #22 để khi tách ra vẫn giữ được định dạng (độ rộng) của các cột như sheet gốc
Tức gốc thế nào thì kết quả thế nấy, không giống AutoFit tí nào cả
Tôi cho rằng Copy/Paste Column Widths mới đúng
 
Upvote 0
Tôi e rằng cái chỗ mới thêm vào là: TRẬT LẤT. Bởi người ta yêu cầu:

Tức gốc thế nào thì kết quả thế nấy, không giống AutoFit tí nào cả
Tôi cho rằng Copy/Paste Column Widths mới đúng
Chính xác rồi thầy ạ! Đúng là em ko đọc kĩ yêu cầu tác giả.
 
Upvote 0

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

Back
Top Bottom