Nhờ viết Sub trình bày lại dữ liệu trong bảng tính

Liên hệ QC

TrungChinhs

Thành viên tích cực
Tham gia
18/2/08
Bài viết
1,475
Được thích
2,469
Nghề nghiệp
Công chức
Chào các bạn! Trước đây tôi có tạo một kiểu bảng dữ liệu nguồn nhưng để nay cần thay đổi lại cách trình bày dữ liệu để vận dụng một số Sub trên GPE cho việc tự động hoá bảng tính (mẫu biểu và yêu cầu cụ thể trong file đính kèm). Nhờ các Bạn viết code giùm. Xin cảm ơn!
 

File đính kèm

Sắp xếp lại dữ liệu sao ko dùng Pivot Table hả bạn. Các bài viết về Pivot Table sẽ có ích cho bạn đó.
 
Upvote 0
Bạn kiểm lại & viết thêm về số TT mới, nha!

PHP:
Option Explicit
Sub ChuyenDoiDuLieu()
 Dim lRow As Long, lChuHo As Long
 Dim cRng As Range
 Application.ScreenUpdating = False
 Columns("C:C").Select:           Selection.Insert Shift:=xlToRight
 [C1] = "NhanKhau":                 lRow = [b65500].End(xlUp).Row
 Range("A3:A" & lRow).SpecialCells(xlCellTypeConstants, 1).Select
 Selection.EntireRow.Insert
  lRow = [b65500].End(xlUp).Row:          lChuHo = 2
  Do
   If lChuHo > lRow Then Exit Do
   Set cRng = Cells(lChuHo, "B").End(xlDown)
   Range(Cells(lChuHo, "B").Offset(1, 1), Cells(cRng.Row, "B").Offset(1, 1)) _
      = Range(Cells(lChuHo, "B"), Cells(cRng.Row, "B")).Value
   Range(Cells(lChuHo + 1, "B"), cRng).Value = ""
   Range(Cells(lChuHo, "B").Offset(1, 2), cRng.Offset(1, 3)) = _
      Range(Cells(lChuHo, "B").Offset(, 2), cRng.Offset(, 3)).Value
   Cells(lChuHo, "B").Offset(, 2).Resize(, 2).Value = ""
   lChuHo = cRng.Row + 2
  Loop
  
End Sub

Một điểm cần chú ý nữa là nếu hộ chỉ 1 nhân khẩu sẽ sai; Nhưng do bạn không đưa ra trong ví dụ về hộ 1 nhân khẩu, nên chưa viết trong macro (!)
Thứ đến: Trước khi cho macro chạy, bạn phải copy từ bản lưu sang sheet nào đó & tại đó ta réo macro ra!

Chúc vui!!
 

File đính kèm

Upvote 0
PHP:
Option Explicit
Sub ChuyenDoiDuLieu()
 Dim lRow As Long, lChuHo As Long
 Dim cRng As Range
 Application.ScreenUpdating = False
 Columns("C:C").Select:           Selection.Insert Shift:=xlToRight
 [C1] = "NhanKhau":                 lRow = [b65500].End(xlUp).Row
 Range("A3:A" & lRow).SpecialCells(xlCellTypeConstants, 1).Select
 Selection.EntireRow.Insert
  lRow = [b65500].End(xlUp).Row:          lChuHo = 2
  Do
   If lChuHo > lRow Then Exit Do
   Set cRng = Cells(lChuHo, "B").End(xlDown)
   Range(Cells(lChuHo, "B").Offset(1, 1), Cells(cRng.Row, "B").Offset(1, 1)) _
      = Range(Cells(lChuHo, "B"), Cells(cRng.Row, "B")).Value
   Range(Cells(lChuHo + 1, "B"), cRng).Value = ""
   Range(Cells(lChuHo, "B").Offset(1, 2), cRng.Offset(1, 3)) = _
      Range(Cells(lChuHo, "B").Offset(, 2), cRng.Offset(, 3)).Value
   Cells(lChuHo, "B").Offset(, 2).Resize(, 2).Value = ""
   lChuHo = cRng.Row + 2
  Loop
  
End Sub
Một điểm cần chú ý nữa là nếu hộ chỉ 1 nhân khẩu sẽ sai; Nhưng do bạn không đưa ra trong ví dụ về hộ 1 nhân khẩu, nên chưa viết trong macro (!)
Thứ đến: Trước khi cho macro chạy, bạn phải copy từ bản lưu sang sheet nào đó & tại đó ta réo macro ra!

Chúc vui!!

Cảm ơn Bác ! đúng là có một số trường hợp hộ chỉ có một người (hộ độc thân) khi gửi bài em không nghĩ đến vậy mong Bác tiếp tục giúp đỡ (em đang chờ trên máy). Cảm ơn Bác nhiều !
 
Upvote 0
Cảm ơn Bác ! đúng là có một số trường hợp hộ chỉ có một người (hộ độc thân) khi gửi bài em không nghĩ đến vậy mong Bác tiếp tục giúp đỡ (em đang chờ trên máy). Cảm ơn Bác nhiều !

PHP:
Option Explicit
Sub ChuyenDoiDuLieu()
 Dim lRow As Long, lChuHo As Long
 Dim cRng As Range
 Application.ScreenUpdating = False
 Columns("C:C").Select:           Selection.Insert Shift:=xlToRight
 [C1] = "NhanKhau":                 lRow = [b65500].End(xlUp).Row
 Set cRng = Range("A3:A" & lRow).SpecialCells(xlCellTypeConstants, 1)
 For lChuHo = 3 To lRow + cRng.Count
   If Cells(lChuHo, "A").Value <> "" Then
      Cells(lChuHo, "A").EntireRow.Insert
      lChuHo = 1 + lChuHo
   End If
 Next lChuHo
  lRow = [b65500].End(xlUp).Row:          lChuHo = 2
  Do
   If lChuHo > lRow Then Exit Do
 
   If Cells(lChuHo + 1, "B") <> "" Then
      Set cRng = Cells(lChuHo, "B").End(xlDown)
 
      Range(Cells(lChuHo, "B").Offset(1, 1), Cells(cRng.Row, "B").Offset(1, 1)) _
         = Range(Cells(lChuHo, "B"), Cells(cRng.Row, "B")).Value
      Range(Cells(lChuHo + 1, "B"), cRng).Value = ""
      Range(Cells(lChuHo, "B").Offset(1, 2), cRng.Offset(1, 3)) = _
         Range(Cells(lChuHo, "B").Offset(, 2), cRng.Offset(, 3)).Value
      Cells(lChuHo, "B").Offset(, 2).Resize(, 2).Value = ""
      lChuHo = cRng.Row + 2
   Else
      Cells(lChuHo + 1, "C") = Cells(lChuHo, "B").Value
      Cells(lChuHo + 1, "D").Resize(, 2) = Cells(lChuHo, "D").Resize(, 2).Value
      Cells(lChuHo, "D").Resize(, 2).Value = ""
      lChuHo = lChuHo + 2
   End If
  Loop
End Sub

Chắc đợi đã lâu & Không thể nhanh hơn! Do lão hóa í mà!
 
Upvote 0
Đường vòng nhưng ngắn hơn; Ngắn hơn chưa hẵn nhanh hơn

Mời các bạn ngâm cứu biến thể của macro trên, như sau:
PHP:
Option Explicit
Sub ChuyenDoiDuLieu()
 Dim lRow As Long, lChuHo As Long
 Dim cRng As Range

 Application.ScreenUpdating = False
 Columns("C:C").Select:           Selection.Insert Shift:=xlToRight
 [C1] = "NhanKhau":                 lRow = [b65500].End(xlUp).Row
 Set cRng = Range("A3:A" & lRow).SpecialCells(xlCellTypeConstants, 1)
 For lChuHo = 3 To lRow + cRng.Count
   If Cells(lChuHo, "A").Value <> "" Then
      Cells(lChuHo, "A").EntireRow.Insert
      lChuHo = 1 + lChuHo
   End If
 Next lChuHo
 lRow = [b65500].End(xlUp).Row:          lChuHo = 2
 Do
   If lChuHo > lRow Then Exit Do
   With Cells(lChuHo, "B")
      If .Offset(1) <> "" Then
         Set cRng = .End(xlDown)
      Else
         Set cRng = Cells(lChuHo, "B")
      End If
      Range(.Offset(1, 1), Cells(cRng.Row, "B").Offset(1, 1)) _
         = Range(Cells(lChuHo, "B"), Cells(cRng.Row, "B")).Value
      Range(.Offset(1, 2), cRng.Offset(1, 3)) = _
         Range(.Offset(, 2), cRng.Offset(, 3)).Value
      Range(.Offset(1), cRng).Value = ""
      .Offset(, 2).Resize(, 2).Value = ""
      lChuHo = cRng.Row + 2
   End With
 Loop
End Sub
 
Upvote 0
Mời các bạn ngâm cứu biến thể của macro trên, như sau:
PHP:
Option Explicit
Sub ChuyenDoiDuLieu()
 Dim lRow As Long, lChuHo As Long
 Dim cRng As Range

 Application.ScreenUpdating = False
 Columns("C:C").Select:           Selection.Insert Shift:=xlToRight
 [C1] = "NhanKhau":                 lRow = [b65500].End(xlUp).Row
 Set cRng = Range("A3:A" & lRow).SpecialCells(xlCellTypeConstants, 1)
 For lChuHo = 3 To lRow + cRng.Count
   If Cells(lChuHo, "A").Value <> "" Then
      Cells(lChuHo, "A").EntireRow.Insert
      lChuHo = 1 + lChuHo
   End If
 Next lChuHo
 lRow = [b65500].End(xlUp).Row:          lChuHo = 2
 Do
   If lChuHo > lRow Then Exit Do
   With Cells(lChuHo, "B")
      If .Offset(1) <> "" Then
         Set cRng = .End(xlDown)
      Else
         Set cRng = Cells(lChuHo, "B")
      End If
      Range(.Offset(1, 1), Cells(cRng.Row, "B").Offset(1, 1)) _
         = Range(Cells(lChuHo, "B"), Cells(cRng.Row, "B")).Value
      Range(.Offset(1, 2), cRng.Offset(1, 3)) = _
         Range(.Offset(, 2), cRng.Offset(, 3)).Value
      Range(.Offset(1), cRng).Value = ""
      .Offset(, 2).Resize(, 2).Value = ""
      lChuHo = cRng.Row + 2
   End With
 Loop
End Sub

To Bác HYen và Bác SA_DQ: đoạn Code của Bác HYen thì cho kết quả đúng nhưng Cde của Bác SA_DQ có 1 lỗi là khi hộ chỉ có 1 người (hộ độc thân) thì cột chủ hộ sẽ không có tên

Nhờ các Bác chỉ giúp lỗi đó ở chỗ nào. Thanks !
 
Lần chỉnh sửa cuối:
Upvote 0
Một cách khác, trong khi tìm cách khắc phục lỗi

Dùng chủ yếu phương thức .Cut

PHP:
Option Explicit
Sub ChuyenDuLieu()
 Dim lRow As Long, lChuHo As Long, lZz As Long
 Dim cRng As Range:                       Dim sChuHo As String

 Application.ScreenUpdating = False
 Range([d1], [e1]) = Range([c1], [d1]).Value
 [c1] = "NhanKhau":                 lRow = [b65500].End(xlUp).Row
 Set cRng = Range("A3:A" & lRow).SpecialCells(xlCellTypeConstants, 1)
 
 For lChuHo = 3 To lRow + cRng.Count
   If Cells(lChuHo, "A").Value <> "" Then
      Cells(lChuHo, "A").EntireRow.Insert
      lChuHo = 1 + lChuHo
   End If
 Next lChuHo
 lRow = [b65500].End(xlUp).Row:           lChuHo = 2
 Do
   If lChuHo > lRow Then Exit Do
   With Cells(lChuHo, "B")
      sChuHo = .Value
      If .Offset(1) <> "" Then
         lZz = .End(xlDown).Row
         Set cRng = .Offset().Resize(1 + lZz - .Row, 3)
      Else
         Set cRng = .Offset().Resize(, 3)
         lZz = .Row
      End If
      cRng.Cut:                           .Offset(1, 1).Select
      ActiveSheet.Paste
      Cells(lChuHo, "B") = sChuHo  '<<=='
      lChuHo = lZz + 2
   End With
 Loop
End Sub

Nhưng lại phát sinh vấn đề ngoài lề tại lệnh sau .Cut
 
Upvote 0
Cải thiện tốc độ lần sau cùng

Thay vì duyệt qua toàn bộ từng nhân khẩu, ta chỉ duyệt các chủ hộ mà thôi:
PHP:
Option Explicit
Sub ChuyenDuLieu()
 Dim lRow As Long, lChuHo As Long, lZz As Long
 Dim cRng As Range, RLe As Range, RCh As Range
 Dim sChuHo As String

 Application.ScreenUpdating = False
 Range([d1], [e1]) = Range([c1], [d1]).Value
 [c1] = "NhanKhau":                       lRow = [b65500].End(xlUp).Row
 For Each cRng In Range("A3:A" & lRow).SpecialCells(xlCellTypeConstants, 1)
   If cRng.Row Mod 2 = 1 Then
      If RCh Is Nothing Then
         Set RCh = cRng
      Else
         Set RCh = Union(RCh, cRng)
      End If
   Else
      If RLe Is Nothing Then
         Set RLe = cRng
      Else
         Set RLe = Union(RLe, cRng)
      End If
   End If
 Next cRng
 RLe.EntireRow.Insert:                    Set RLe = Nothing
 RCh.EntireRow.Insert:                    Set RCh = Nothing
 lRow = [b65500].End(xlUp).Row:           lChuHo = 2
 Do
   If lChuHo > lRow Then Exit Do
   With Cells(lChuHo, "B")
      sChuHo = .Value
      If .Offset(1) <> "" Then
         lZz = .End(xlDown).Row
         Set cRng = .Offset().Resize(1 + lZz - .Row, 3)
      Else
         Set cRng = .Offset().Resize(, 3)
         lZz = .Row
      End If
      cRng.Cut Destination:=.Offset(1, 1)
      Application.CutCopyMode = False
      Cells(lChuHo, "B") = sChuHo  '<<=='
      lChuHo = lZz + 2
   End With
 Loop
End Sub
 
Upvote 0
Mã:
Option Explicit
Sub ChuyenDuLieu()
 Dim lRow As Long, lChuHo As Long, lZz As Long
 Dim cRng As Range, RLe As Range, RCh As Range
 Dim sChuHo As String
 
 Application.ScreenUpdating = False
 Range([d1], [e1]) = Range([c1], [d1]).Value
 [c1] = "NhanKhau":                       lRow = [b65500].End(xlUp).Row
 For Each cRng In Range("A3:A" & lRow).SpecialCells(xlCellTypeConstants, 1)
   If cRng.Row Mod 2 = 1 Then
      If RCh Is Nothing Then
         Set RCh = cRng
      Else
         Set RCh = Union(RCh, cRng)
      End If
   Else
      If RLe Is Nothing Then
         Set RLe = cRng
      Else
         Set RLe = Union(RLe, cRng)
      End If
   End If
 Next cRng
 RLe.EntireRow.Insert:                    Set RLe = Nothing
 RCh.EntireRow.Insert:                    Set RCh = Nothing
 lRow = [b65500].End(xlUp).Row:           lChuHo = 2
 Do
   If lChuHo > lRow Then Exit Do
   With Cells(lChuHo, "B")
      sChuHo = .Value
      If .Offset(1) <> "" Then
         lZz = .End(xlDown).Row
         Set cRng = .Offset().Resize(1 + lZz - .Row, 3) [COLOR=royalblue]'<<===[/COLOR]
      Else
         Set cRng = .Offset().Resize(, 3) [COLOR=royalblue]'<<===[/COLOR]
         lZz = .Row
      End If
      cRng.Cut Destination:=.Offset(1, 1)
      Application.CutCopyMode = False
      Cells(lChuHo, "B") = sChuHo  [COLOR=royalblue]'<<=='[/COLOR]
      lChuHo = lZz + 2
   End With
 Loop
End Sub
Các bác giải thích cho em rõ ở chỗ: (Các dòng lệnh em đã tô màu xanh phía trên)
.Offset() có phải/ có thể thay bằng .Offset(0,0) được không
Và Dòng Cells(lChuHo, "B") = sChuHo
Sao lại không thay được bằng .Offset() = sChuHo hay .Offset(0,0) = sChuHo ?
Xin cảm ơn trước, các bác nhé! Rất cảm ơn!
 
Lần chỉnh sửa cuối:
Upvote 0
Các bác giải thích cho em rõ ở chỗ: (Các dòng lệnh em đã tô màu xanh phía trên)
.Offset() có phải/ có thể thay bằng .Offset(0,0) được không
Tôi nghĩ là đúng vậy đấy! (thí nghiệm)... Nhưng không hiểu là tại sao lại không bỏ luôn nó nhỉ (cho Offset() vào nhằm mục đích gì?)
Ví dụ:
Set cRng = .Offset().Resize(1 + lZz - .Row, 3)
thì tại sao không là:
Set cRng = .Resize(1 + lZz - .Row, 3)
Và Dòng Cells(lChuHo, "B") = sChuHo
Sao lại không thay được bằng .Offset() = sChuHo hay .Offset(0,0) = sChuHo ?
Còn tôi thì cho rằng tại sao không là :
 
Upvote 0
Tôi nghĩ là đúng vậy đấy! (thí nghiệm)... Nhưng không hiểu là tại sao lại không bỏ luôn nó nhỉ (cho .Offset() vào nhằm mục đích gì?)
Ví dụ:
Đúng là những anh chàng này bỏ được. Mình thử bỏ rồi, không có chuyện gì sẫy ra
thì tại sao không là: .Offset() = sChuHo
Còn tôi thì cho rằng tại sao không là : .Value = sChuHo
thì không được bạn à!
Mình thử thêm dòng lệnh MsgBox .Address sau dòng lệnh .Cut, thì được biết rằng cái chàng .Cut nó làm thay đổi địa chỉ các ô trong cRng rồi!

Muốn hiễn thị đúng ý đồ tác giả, ta lại phải ghi
.Offset(-1 , -1) thay vì .Value như bạn hay .Offset(0,0) như mình nghỉ!

Dù gì cũng rất cảm ơn bạn đã quan tâm & có ý kiến!
 
Upvote 0
Web KT

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

Back
Top Bottom