Nhờ các Anh, Chị giúp đỡ code cho nút lệnh tách mỗi lớp trong danh sách thành 1 sheet ạ!

Liên hệ QC
Tôi tuân thủ nội quy khi đăng bài

2013myvietnam

Thành viên mới
Tham gia
5/6/23
Bài viết
10
Được thích
2
Em có danh sách học sinh tuyển sinh vào lớp 6 ở Sheet DK_TS như ảnh dưới. Sau khi xếp lớp, em muốn tạo nút lệnh Tách lớp để tách mỗi lớp trong cột Xếp lớp thành 1 Sheet riêng và đặt tên sheet theo tên các lớp nhưng không biết viết code như thế nào cho nút lệnh. Các anh, chị giúp đỡ em với, em xin chân thành cảm ơn ạ!

Tach lop.png
 

File đính kèm

  • 1. DANH SACH HS ĐANG KI TS VAO L6 (2023-2024).xls
    98 KB · Đọc: 42
Các Anh, Chị giúp đỡ em với ạ!
Làm gì nóng nảy vậy.
Lỗi file của bạn trình bày hắc ám quá. Nơi bạn muốn lấy dữ liệu không chứa dữ liệu theo dạng dễ hiểu, dễ trích. Nó là một bảng báo cáo màu mè nhìn không ra.
Theo thống kê này, đã có rất nhiều lượt người ta vào xem thử (xem con số "đọc") mà thấy rắc rối quá nên họ còn phải nghiên cứu.

1685974741040.png
 
Upvote 0
Em có danh sách học sinh tuyển sinh vào lớp 6 ở Sheet DK_TS như ảnh dưới. Sau khi xếp lớp, em muốn tạo nút lệnh Tách lớp để tách mỗi lớp trong cột Xếp lớp thành 1 Sheet riêng và đặt tên sheet theo tên các lớp nhưng không biết viết code như thế nào cho nút lệnh. Các anh, chị giúp đỡ em với, em xin chân thành cảm ơn ạ!

View attachment 291063
Bạn thử code này xem sao.
Mã:
Option Explicit
Private Sub DeleteSheet()
    Dim sh As Worksheet
    For Each sh In ThisWorkbook.Worksheets
        If sh.Name <> Sheet1.Name Then sh.Delete
    Next sh
End Sub
Private Sub DeleteData(Rng As Range, Key As String)
    Dim aCell As Range, RngDel As Range, aRow As Integer
    Dim STT() As Integer
    aRow = 0
    Rng.Parent.Shapes("Rounded Rectangle 3").Delete
    For Each aCell In Rng
        If aCell.Value <> Key Then
            If RngDel Is Nothing Then
                Set RngDel = aCell
            Else
                Set RngDel = Union(aCell, RngDel)
            End If
        Else
            aRow = aRow + 1
            ReDim Preserve STT(1 To aRow)
            STT(aRow) = aRow
        End If
    Next aCell
    If Not RngDel Is Nothing Then
        RngDel.EntireRow.Delete
        Rng.Parent.Range("A10:A" & (aRow + 9)).Value = Application.Transpose(STT)
    End If
    Rng.Parent.Name = Key
End Sub
Sub TachSheet()
    Dim Wh As Worksheet
    Dim Dic As Object, Arr, aRow As Integer, i As Integer
    Application.DisplayAlerts = False
    With Sheet1
        aRow = .Range("U10000").End(xlUp).Row
        If aRow < 10 Then Exit Sub
        .Sort.SortFields.Clear
        .Range("B9:V" & aRow).Sort Key1:=Range("U9"), Header:=xlYes
        DeleteSheet
        Set Dic = CreateObject("Scripting.Dictionary")
        Arr = .Range("U10:U" & aRow).Value
        For i = 1 To UBound(Arr)
            If Arr(i, 1) <> "" And Dic.Exists(Arr(i, 1)) = False Then
                Dic.Add Arr(i, 1), ""
                .Copy After:=Sheets(Sheets.Count)
                Set Wh = ActiveSheet
                Call DeleteData(Wh.Range("U10:U" & aRow), CStr(Arr(i, 1)))
            End If
        Next i
        Set Dic = Nothing
    End With
    Set Wh = Nothing
    Application.DisplayAlerts = True
    MsgBox "Da tach xong"
End Sub
 
Upvote 0
Bạn thử code này xem sao.
Mã:
Option Explicit
Private Sub DeleteSheet()
    Dim sh As Worksheet
    For Each sh In ThisWorkbook.Worksheets
        If sh.Name <> Sheet1.Name Then sh.Delete
    Next sh
End Sub
Private Sub DeleteData(Rng As Range, Key As String)
    Dim aCell As Range, RngDel As Range, aRow As Integer
    Dim STT() As Integer
    aRow = 0
    Rng.Parent.Shapes("Rounded Rectangle 3").Delete
    For Each aCell In Rng
        If aCell.Value <> Key Then
            If RngDel Is Nothing Then
                Set RngDel = aCell
            Else
                Set RngDel = Union(aCell, RngDel)
            End If
        Else
            aRow = aRow + 1
            ReDim Preserve STT(1 To aRow)
            STT(aRow) = aRow
        End If
    Next aCell
    If Not RngDel Is Nothing Then
        RngDel.EntireRow.Delete
        Rng.Parent.Range("A10:A" & (aRow + 9)).Value = Application.Transpose(STT)
    End If
    Rng.Parent.Name = Key
End Sub
Sub TachSheet()
    Dim Wh As Worksheet
    Dim Dic As Object, Arr, aRow As Integer, i As Integer
    Application.DisplayAlerts = False
    With Sheet1
        aRow = .Range("U10000").End(xlUp).Row
        If aRow < 10 Then Exit Sub
        .Sort.SortFields.Clear
        .Range("B9:V" & aRow).Sort Key1:=Range("U9"), Header:=xlYes
        DeleteSheet
        Set Dic = CreateObject("Scripting.Dictionary")
        Arr = .Range("U10:U" & aRow).Value
        For i = 1 To UBound(Arr)
            If Arr(i, 1) <> "" And Dic.Exists(Arr(i, 1)) = False Then
                Dic.Add Arr(i, 1), ""
                .Copy After:=Sheets(Sheets.Count)
                Set Wh = ActiveSheet
                Call DeleteData(Wh.Range("U10:U" & aRow), CStr(Arr(i, 1)))
            End If
        Next i
        Set Dic = Nothing
    End With
    Set Wh = Nothing
    Application.DisplayAlerts = True
    MsgBox "Da tach xong"
End Sub
Em đã chạy thử Code trên và đã thành công rồi ạ! Em cảm ơn Anh nhiều ạ!
 
Upvote 0
Bạn thử code này xem sao.
Mã:
Option Explicit
Private Sub DeleteSheet()
    Dim sh As Worksheet
    For Each sh In ThisWorkbook.Worksheets
        If sh.Name <> Sheet1.Name Then sh.Delete
    Next sh
End Sub
Private Sub DeleteData(Rng As Range, Key As String)
    Dim aCell As Range, RngDel As Range, aRow As Integer
    Dim STT() As Integer
    aRow = 0
    Rng.Parent.Shapes("Rounded Rectangle 3").Delete
    For Each aCell In Rng
        If aCell.Value <> Key Then
            If RngDel Is Nothing Then
                Set RngDel = aCell
            Else
                Set RngDel = Union(aCell, RngDel)
            End If
        Else
            aRow = aRow + 1
            ReDim Preserve STT(1 To aRow)
            STT(aRow) = aRow
        End If
    Next aCell
    If Not RngDel Is Nothing Then
        RngDel.EntireRow.Delete
        Rng.Parent.Range("A10:A" & (aRow + 9)).Value = Application.Transpose(STT)
    End If
    Rng.Parent.Name = Key
End Sub
Sub TachSheet()
    Dim Wh As Worksheet
    Dim Dic As Object, Arr, aRow As Integer, i As Integer
    Application.DisplayAlerts = False
    With Sheet1
        aRow = .Range("U10000").End(xlUp).Row
        If aRow < 10 Then Exit Sub
        .Sort.SortFields.Clear
        .Range("B9:V" & aRow).Sort Key1:=Range("U9"), Header:=xlYes
        DeleteSheet
        Set Dic = CreateObject("Scripting.Dictionary")
        Arr = .Range("U10:U" & aRow).Value
        For i = 1 To UBound(Arr)
            If Arr(i, 1) <> "" And Dic.Exists(Arr(i, 1)) = False Then
                Dic.Add Arr(i, 1), ""
                .Copy After:=Sheets(Sheets.Count)
                Set Wh = ActiveSheet
                Call DeleteData(Wh.Range("U10:U" & aRow), CStr(Arr(i, 1)))
            End If
        Next i
        Set Dic = Nothing
    End With
    Set Wh = Nothing
    Application.DisplayAlerts = True
    MsgBox "Da tach xong"
End Sub
Code chạy tuyệt vời mà nhìn hoa cả mắt
 
Upvote 0
Một cách tiếp cận khác.
Nhân bản sheet gốc lên thành nhiều sheet cho mỗi lớp 1 sheet.

PHP:
Option Explicit
Sub tachlop()
Dim lr&, i&, j&, k&, lop(1 To 10000, 1 To 1), rng, tmp As String
Dim ws As Worksheet

'Xoa sheet cu, tao array chua data
For Each ws In Sheets
    If ws.Name <> "DK_TS" Then ws.Delete
Next
lr = Cells(Rows.Count, "U").End(xlUp).Row
rng = Range("U10:U" & lr).Value

'tao array chua danh sach lop (khong trung)
With CreateObject("Scripting.Dictionary")
    For i = 1 To UBound(rng)
        If rng(i, 1) <> "" Then
            If Not .exists(rng(i, 1)) Then
                .Add rng(i, 1), ""
                k = k + 1: lop(k, 1) = rng(i, 1)
            End If
        End If
    Next
End With

'Xep lai danh sach lop theo thu tu tang dan
For i = 1 To k - 1
    For j = i + 1 To k
        If lop(i, 1) > lop(j, 1) Then
            tmp = lop(j, 1)
            lop(j, 1) = lop(i, 1)
            lop(i, 1) = tmp
        End If
    Next
Next

'Copy sheet goc ra nhieu sheet, dat ten sheet theo tung lop va delete dong cua cac lop khac
With Application
    .CopyObjectsWithCells = False
    .ScreenUpdating = False
    For i = 1 To k
        Sheets("DK_TS").Copy after:=Sheets(Sheets.Count)
        ActiveSheet.Name = lop(i, 1)
        For j = lr To 10 Step -1
            If Cells(j, "U").Value <> lop(i, 1) Then Rows(j).Delete
        Next
    Next
    .CopyObjectsWithCells = True
    .ScreenUpdating = True
    .CutCopyMode = False
End With
End Sub
 

File đính kèm

  • Danhsach.xlsm
    29.5 KB · Đọc: 15
Upvote 0
Thấy chưa bạn, mới hơn 1 giờ từ lúc tôi nói là có người giúp rồi. :D
Tôi thì vẫn còn đang thử xem dữ liệu ấy còn làm gì được nữa.
Một bảng chi tiết thế mà chỉ tách ra từng lớp thì là dân gà mờ quá.

Bảng này nếu là tôi thì để mặc cái bảng báo cáo hoa lá cành ấy. Tôi tìm cách tách phần dữ liệu ra để sau này phân tích cho gọn gàng, nhanh chóng, và dễ hiểu (lý giải).

1. Hoặc dùng Power Query cho nó vào một Data Model

2. Hoặc tạo một sheet phụ:
2.1. Tạo tiêu đề ở dòng 1
2.2. Tạo một Named Range CHI_TIET, bao gồm cái range chứa dữ liệu
2.2. Paste cái name này vào A2
2.3. Đổi bảng thành Table.

Từ Data Model hay Table (sheet phụ), ta có thể lọc, hoặc advanced filter thành nhiều bảng để đáp ứng yêu cầu.

Từ những thứ này về sau còn có thể phân tích dữ liệu ở trình độ cao hơn.

Một trong những cái hại của VBA là người ta thấy hơi khó chút đã lo code, không chịu động não cho các phương pháp khác. Cái nhìn chỉ chuyên về "tăng tốc code". Rốt cuộc chỉ giỏi code mà tầm nhìn xa thì không phát triển.
 
Upvote 0
Viết đơn giản và bình dân:
Mã:
Sub DeleteSheet()
Application.DisplayAlerts = False
    Dim sh As Worksheet
    For Each sh In ThisWorkbook.Worksheets
        If sh.Name <> Sheet1.Name Then sh.Delete
    Next sh
Application.DisplayAlerts = True
End Sub
Mã:
Sub SplitSheet()
Dim DictClass, SArr(), RArr(), ClassList(), ClassArr()
Dim LastRw As Long, NextRw As Long
DeleteSheet
Set DictClass = CreateObject("Scripting.Dictionary")
With Sheet1
    LastRw = .[U2000].End(xlUp).Row
    SArr = .Range("A10:V" & LastRw).Value
    ClassList = .Range("U10:U" & LastRw).Value
End With
For i = 1 To UBound(ClassList, 1)
    If Not DictClass.exists(ClassList(i, 1)) Then
        k = k + 1
        DictClass.Add ClassList(i, 1), k
    End If
Next
For i = 1 To DictClass.Count
    ReDim RArr(1 To LastRw, 1 To 22)
    ClassArr = DictClass.keys
    k = 0
    For m = 1 To UBound(ClassList, 1)
        If SArr(m, 21) = ClassArr(i - 1) Then
            k = k + 1
            RArr(k, 1) = k
            For n = 2 To 22
                RArr(k, n) = SArr(m, n)
            Next
        End If
    Next
    Sheet1.Copy After:=Sheets(Sheets.Count)
    With ActiveSheet
        .Name = ClassArr(i - 1)
        .Range("A10:V1000").ClearContents
        .[A10].Resize(k, 22).Value = RArr
        NextRw = .[B100].End(xlUp).Row + 1
        Sheet1.Range("A" & LastRw + 1).Resize(12, 22).Copy .Range("A" & NextRw)
    End With
Next
  
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Đít sần có thể đơn giản nhưng không hề bình dân.
Quan điểm của tôi, bình dân phải có tính chất "ở đâu cũng được.". Đít sần chỉ mài được trên nền tảng Windows.
Bài ni nếu bình dân là sort theo lớp, xong chạy từ trên xuống dưới, túm từng lớp copy sang sheet đích
 
Upvote 0
Đít sần có thể đơn giản nhưng không hề bình dân.
Đồng ý là Diction không bình dân, nhưng thuật toán bình dân: lụm từng lớp tạo sheet mới, và bình dân ở chỗ copy paste cái footer.
Bài ni nếu bình dân là sort theo lớp, xong chạy từ trên xuống dưới, túm từng lớp copy sang sheet đích
cùng thuật toán túm từng lớp tạo sheet mới, chỉ là công cụ, thủ thuật khác nhau.

Viết lại, cũng thuật toán đơn giản trên, cũng có Dict, nhưng thay vì duyệt mảng nguồn 3 lần (tương ứng 3 lớp) thì chỉ duyệt 1 lần, thủ thuật là dùng mảng trong mảng. Nếu so sánh code bài #14 thì code #14 chiếm dụng thời gian, code sau đây chiếm dụng không gian.

Mã:
Sub SplitSheet2()
Dim DictClass, SArr(), RArr(), ClassList(), ClassArr(), RArrChild()
Dim LastRw As Long, NextRw As Long, RwCount()
DeleteSheet
Set DictClass = CreateObject("Scripting.Dictionary")
With Sheet1
    LastRw = .[U2000].End(xlUp).Row
    SArr = .Range("A10:V" & LastRw).Value
    ClassList = .Range("U10:U" & LastRw).Value
End With
For i = 1 To UBound(ClassList, 1)
    If Not DictClass.exists(ClassList(i, 1)) Then
        k = k + 1
        DictClass.Add ClassList(i, 1), k
    End If
Next
    ClassArr = DictClass.keys
    ReDim RArr(1 To k)
    ReDim RwCount(1 To k)
    ReDim RArrChild(1 To UBound(SArr, 1), 1 To 22)
For i = 1 To k
    RArr(i) = RArrChild
Next
    For m = 1 To UBound(ClassList, 1)
        x = DictClass.Item(ClassList(m, 1))
        RwCount(x) = RwCount(x) + 1
        For n = 1 To 22
            RArr(x)(RwCount(x), n) = SArr(m, n)
        Next
    Next
For i = 1 To k
    Sheet1.Copy After:=Sheets(Sheets.Count)
    With ActiveSheet
        .Name = ClassArr(i - 1)
        .Range("A10:V1000").ClearContents
        .[A10].Resize(RwCount(i), 22).Value = RArr(i)
        NextRw = .[B100].End(xlUp).Row + 1
        Sheet1.Range("A" & LastRw + 1).Resize(12, 22).Copy .Range("A" & NextRw)
    End With
Next
End Sub
 
Upvote 0
Không dùng Dic cũng không cần sort dữ liệu gốc theo lớp
Mã:
Sub XYZ()
  Dim sh  As Worksheet, shDelete, arr(), sRow&, i&, tmp$
  Application.ScreenUpdating = False
  Application.DisplayAlerts = False
  Set sh = Sheets("DK_TS")
  i = sh.Range("U100000").End(xlUp).Row
  If i < 10 Then Exit Sub
  arr = sh.Range("A10:V" & i).Value
  tmp = "|"
  sRow = UBound(arr)
  Call DeleteSheet(shDelete, Sheets("DK_TS").Name)
  For i = 1 To sRow
    If arr(i, 21) <> "" Then
      If InStr(1, tmp, "|" & arr(i, 21) & "|", vbTextCompare) = 0 Then
        tmp = tmp & arr(i, 21) & "|"
        Call AddSheet(sh, sRow, arr, arr(i, 21))
      End If
    End If
  Next i
  Application.DisplayAlerts = True
  Application.ScreenUpdating = True
  MsgBox "Da tach xong"
End Sub

Private Sub DeleteSheet(shDelete, ByVal shName$)
  For Each shDelete In ThisWorkbook.Worksheets
    If shDelete.Name <> shName Then shDelete.Delete
  Next shDelete
End Sub

Private Sub AddSheet(sh, sRow&, ByVal res, ByVal lop As String)
    Dim i&, k&, j&
    sh.Copy After:=Sheets(Sheets.Count)
    ActiveSheet.Name = lop
    ActiveSheet.Shapes("Rounded Rectangle 3").Delete
    For i = 1 To sRow
      If res(i, 21) = lop Then
        k = k + 1
        res(k, 1) = k
        For j = 2 To UBound(res, 2)
          res(k, j) = res(i, j)
        Next j
      End If
    Next i
    If k < sRow Then Range("A10").Resize(sRow - k).EntireRow.Delete
    Range("A10").Resize(k, UBound(res, 2)) = res
End Sub
 
Upvote 0
Thấy chủ đề này cũng vui quá, nhưng chắc chủ thớt đã không còn quan tâm tới nửa, sửa code lại chút cho vui bỏ sắp xếp và đích sần luôn.
Mã:
Option Explicit
Private Sub DeleteSheet()
    Dim sh As Worksheet
    For Each sh In ThisWorkbook.Worksheets
        If sh.Name <> Sheet1.Name Then sh.Delete
    Next sh
End Sub
Function SheetExists(shtName As String, Optional wb As Workbook) As Boolean
  Dim sht As Worksheet
  If wb Is Nothing Then Set wb = ThisWorkbook
  On Error Resume Next
  Set sht = wb.Sheets(shtName)
  On Error GoTo 0
  SheetExists = Not sht Is Nothing
End Function
Private Sub DeleteData(Rng As Range, Key As String)
    Dim aCell As Range, RngDel As Range, aRow As Integer
    Dim STT() As Integer
    aRow = 0
    Rng.Parent.Shapes("Rounded Rectangle 3").Delete
    For Each aCell In Rng
        If aCell.Value <> Key Then
            If RngDel Is Nothing Then
                Set RngDel = aCell
            Else
                Set RngDel = Union(aCell, RngDel)
            End If
        Else
            aRow = aRow + 1
            ReDim Preserve STT(1 To aRow)
            STT(aRow) = aRow
        End If
    Next aCell
    If Not RngDel Is Nothing Then
        RngDel.EntireRow.Delete
        Rng.Parent.Range("A10:A" & (aRow + 9)).Value = Application.Transpose(STT)
    End If
    Rng.Parent.Name = Key
End Sub
Sub TachSheet()
    Dim Wh As Worksheet
    Dim Arr, aRow As Integer, i As Integer
    With Sheet1
        aRow = .Range("U10000").End(xlUp).Row
        If aRow < 10 Then Exit Sub
        Application.DisplayAlerts = False
        DeleteSheet
        Arr = .Range("U10:U" & aRow).Value
        For i = 1 To UBound(Arr)
            If Not SheetExists(CStr(Arr(i, 1))) Then
                .Copy After:=Sheets(Sheets.Count)
                Set Wh = ActiveSheet
                Call DeleteData(Wh.Range("U10:U" & aRow), CStr(Arr(i, 1)))
            End If
        Next i
        Application.DisplayAlerts = True
    End With
    Set Wh = Nothing
    MsgBox "Da tach xong"
End Sub
 
Upvote 0
Thấy chủ đề này cũng vui quá, nhưng chắc chủ thớt đã không còn quan tâm tới nửa, sửa code lại chút cho vui bỏ sắp xếp và đích sần luôn.
Mã:
Option Explicit
Private Sub DeleteSheet()
    Dim sh As Worksheet
    For Each sh In ThisWorkbook.Worksheets
        If sh.Name <> Sheet1.Name Then sh.Delete
    Next sh
End Sub
Function SheetExists(shtName As String, Optional wb As Workbook) As Boolean
  Dim sht As Worksheet
  If wb Is Nothing Then Set wb = ThisWorkbook
  On Error Resume Next
  Set sht = wb.Sheets(shtName)
  On Error GoTo 0
  SheetExists = Not sht Is Nothing
End Function
Private Sub DeleteData(Rng As Range, Key As String)
    Dim aCell As Range, RngDel As Range, aRow As Integer
    Dim STT() As Integer
    aRow = 0
    Rng.Parent.Shapes("Rounded Rectangle 3").Delete
    For Each aCell In Rng
        If aCell.Value <> Key Then
            If RngDel Is Nothing Then
                Set RngDel = aCell
            Else
                Set RngDel = Union(aCell, RngDel)
            End If
        Else
            aRow = aRow + 1
            ReDim Preserve STT(1 To aRow)
            STT(aRow) = aRow
        End If
    Next aCell
    If Not RngDel Is Nothing Then
        RngDel.EntireRow.Delete
        Rng.Parent.Range("A10:A" & (aRow + 9)).Value = Application.Transpose(STT)
    End If
    Rng.Parent.Name = Key
End Sub
Sub TachSheet()
    Dim Wh As Worksheet
    Dim Arr, aRow As Integer, i As Integer
    With Sheet1
        aRow = .Range("U10000").End(xlUp).Row
        If aRow < 10 Then Exit Sub
        Application.DisplayAlerts = False
        DeleteSheet
        Arr = .Range("U10:U" & aRow).Value
        For i = 1 To UBound(Arr)
            If Not SheetExists(CStr(Arr(i, 1))) Then
                .Copy After:=Sheets(Sheets.Count)
                Set Wh = ActiveSheet
                Call DeleteData(Wh.Range("U10:U" & aRow), CStr(Arr(i, 1)))
            End If
        Next i
        Application.DisplayAlerts = True
    End With
    Set Wh = Nothing
    MsgBox "Da tach xong"
End Sub
Mấy hôm hơi bận nên hôm nay em mới vào xem lại ạ! Một lần nữa em xin chân thành cảm ơn các Anh (chị) đã giúp đỡ em hoàn thành được yêu cầu đã đặt ra. Kính chúc các Anh (chị) và gia đình luôn Mạnh khỏe, Hạnh phúc và Thành đạt ạ!
 
Upvote 0
Web KT

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

Back
Top Bottom