Giúp đỡ tính tổng bằng VBA !!!

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

Ninosami

Thành viên mới
Tham gia
16/12/22
Bài viết
6
Được thích
0
Em muốn tỉnh tổng ở các ô bôi vàng bằng Macro nhưn đã loay hoay mấy ngày nay vẫn không được. Nhờ anh/ chị hỗ trợ giúp ạ. Em cám ơn nhiều
 

File đính kèm

  • TONG.png
    TONG.png
    231 KB · Đọc: 45
Đây là file danh sách và macro mình làm thử nhưng chạy không ra được đúng sum tổng ở các dòng dưới:
Sub Tinhtong()
Dim m As Long
Dim rA As Range
For Each rA In Range("C7", Range("F" & Rows.Count).End(xlUp)).SpecialCells(xlConstants, xlNumbers).Areas
rA.Cells(0).Formula = "=SUM(" & rA.Address & ")"
Next rA
End Sub
 

File đính kèm

  • DANH SACH.xlsm
    36.9 KB · Đọc: 11
Upvote 0
Bài này là kinh điển kỹ thuật của nhà băng cuối ngày sort phát sinh, gộp, và tính tổng. Chỉ là ở đây, người ta làm ngược tổng từ dưới lên (ít có, nhưng không hẳn là không ai làm)
Kỹ thuật này chủ yếu làm trên hai tổng (sub/grand totals) và một lính canh (sentinel)
- Tổng chung (grand totals) tích lũy từ đầu chiis chuoios
- Tổng nhỏ (sub totals) được set lại 0 ở đầu mỗi nhóm và tích lũy cho đến cuối nhóm.
- Lính canh dùng để báo hiệu khi đến nhóm mới.

' đạon code dưới đây tôi dùng 1 to 5 là vì lười biếng. Khi code thật, tôi dùng biến hoặc hằng.
Dim totSub(1 To 5) As Double, totGrandt(1 To 5) As Double, totCols Aa Variant
totCols= VBA.Array("", "C", "D", "E", "F", "G")
curLine = ... ' code tìm dòng cuối
Do While Cells(curLine, 1) <> chuỗi ở dòng tổng
If (Cells(curLine, 1) = chuỗi tổng nhóm Then
For i = 1 To 5
Cells(curLine, totCols(i)) = totSub(i)
totGrand(i) = totGrand(i) + totSub(i)
Next i
Erase totSub
Else
For i = 1 To 5
totSub(i) = totSub(i) + Cells(curLine, totCols(i))
Next i
End If
Loop
For i = 1 To 5
Cells(curLine, totCols(i)) = totGrand(i)
Next i

Vì ở bài này dòng cuối mỗi nhóm đã có sẵn cho nên cách làm khá dễ. Bình thường thì phải sử dụng lính canh, so sánh nhóm hiện tại với dòng đang đọc. Nếu gióng thì là còn trong nhóm, nếu khác thì đã qua nhóm mới:
- ghi tổng lại
- xóa các tổng về 0
- chuyển lính canh (nhóm hiện tại = nhốm mới)
Kỹ thuật kinh điển. Tôi chỉ nếu ra đây cho các bạn biết ngày xưa lập trình tổng kết phát sinh là như thế nào.
 
Upvote 0
Đây là file danh sách và macro mình làm thử nhưng chạy không ra được đúng sum tổng ở các dòng dưới:
Sub Tinhtong()
Dim m As Long
Dim rA As Range
For Each rA In Range("C7", Range("F" & Rows.Count).End(xlUp)).SpecialCells(xlConstants, xlNumbers).Areas
rA.Cells(0).Formula = "=SUM(" & rA.Address & ")"
Next rA
End Sub
Dùng mảng code chạy nhay hơn
Mã:
Sub ABC()
Dim sh As Worksheet, rng As Range, TT(), t(), sR&, i&, j&
  Set sh = ThisWorkbook.Sheets("VP_2")
  Set rng = sh.Range("A6:F" & sh.Range("A1000000").End(xlUp).Row)
  sR = rng.Rows.Count
  ReDim TT(1 To 1, 1 To 4)
  ReDim t(1 To 1, 1 To 4)
  For i = sR To 1 Step -1
    If IsNumeric(rng(i, 1)) Then
      For j = 3 To 6
        t(1, j - 2) = t(1, j - 2) + rng(i, j)
        TT(1, j - 2) = TT(1, j - 2) + rng(i, j)
      Next j
    Else
      rng(i, 3).Resize(, 4) = t
      rng(i, 3).Resize(, 4).Font.Bold = True
      ReDim t(1 To 1, 1 To 4)
    End If
  Next i
  sh.Range("C5").Resize(, 4) = TT
End Sub
 
Upvote 0
Thêm vài dòng lệnh từ ý tưởng của #07:

PHP:
Sub ABC_1()
Dim Sh As Worksheet, Rng As Range, TT(), t(), SoDg&, I&, J&, Col As Integer

  Set Sh = ThisWorkbook.Sheets("VP_2")
  Set Rng = Sh.Range("A6:F" & Sh.Range("A1000000").End(xlUp).Row)
  SoDg = Rng.Rows.Count
  ReDim TT(1 To 1, 1 To 4)
  ReDim t(1 To 1, 1 To 4)
  For I = SoDg To 1 Step -1
    If IsNumeric(Rng(I, 1).Value) Then
      For J = 3 To 6
        t(1, J - 2) = t(1, J - 2) + Rng(I, J)
 '       TT(1, J - 2) = TT(1, J - 2) + Rng(I, J)    '
      Next J
    Else
      Rng(I, 3).Resize(, 4) = t
      Rng(I, 3).Resize(, 4).Font.Bold = True
      For Col = 1 To 4
        TT(1, Col) = TT(1, Col) + t(1, Col)
      Next Col
      ReDim t(1 To 1, 1 To 4)
    End If
  Next I
  Sh.Range("C5").Resize(, 4) = TT
End Sub
 
Upvote 0
Chú thêm cho các bạn nào mới bước vào khái niệm dùng mảng:

Các bạn có để ý code bài #6 của tôi dùng Erase để xóa mảng trong khi bài #7 và #8 dùng Redim để làm việc tương tự?
Bạn nào không biết thì lên tiếng tôi sẽ giải thích. Không thấy thì tôi coi như mọi người đều hiểu, chỉ có mình lo xa.
 
Upvote 0
Chú thêm cho các bạn nào mới bước vào khái niệm dùng mảng:

Các bạn có để ý code bài #6 của tôi dùng Erase để xóa mảng trong khi bài #7 và #8 dùng Redim để làm việc tương tự?
Bạn nào không biết thì lên tiếng tôi sẽ giải thích. Không thấy thì tôi coi như mọi người đều hiểu, chỉ có mình lo xa.
Úi bác phức tạp thật. Có lúc bác đưa cơm đến tận mồm, có lúc bác lại vứt cho cái nồi với cái chiếu nhậu. Copy vào nó cứ đỏ lòm là biết cần lửa, lửa xong thấy ... là thiếu gạo, gạo xong lại thấy ? là lại đi tìm rau, mà ở đô thị ra chợ thì lâu lắm, xung quanh không ai làm vườn, thế là nhịn. Thiệt là khó quá đi.
Về vấn đề chính: theo em thì Erase là xóa (không cần google dịch), Dim là định nghĩa biến => Redim là định nghĩa lại biến, mà định nghĩa lại thì nó phải xem cái cũ không tồn tại nghĩa là xóa.
Vì bác nói "việc tương tự" nên em đoán dựa trên code của các bác trên.
Với lại code trên của bác đang đi ngược với triết lý "bấm 1 phát", thứ mà bọn em thích. :wallbash: :wallbash: :wallbash:
 
Upvote 0
Cháu. Phiền chú giải thích giúp. Lỡ có người không biết như cháu nữa. Cám ơn chú ạ
Xem code khai báo. Khi tôi dùng Dim a(1 To 10) thì a được xác định là mảng tĩnh. Khi hai bài kia khai Dim a() thì VBA hiểu là mảng động.
Mảng tĩnh luôn xác định vị trí cố định trong bộ nhớ, và được VBA tạo ngay lúc khai báo. Mảng động chỉ là giành trước tên biến, chưa xác định gì cả (ngoài việc nếu bạn có thêm As kiểu gì đó thì mảng bắt buộc phải là kiểu ấy).

Để trở về trị mặc định (điển hình 0 với kiểu số, "" với kiểu chuỗi,...), mảng động dùng Erase, mảng tĩnh dùng ReDim. Nói cách khác:
1. mảng tĩnh không thể ReDim. Đã tĩnh rồi cón ReDim sửa đổi số cột/dòng khỉ mốc gì nữa.
2. mảng động không thể Erase (không hẳn đúng 100%, xem phần cuối đoạn này sẽ rõ). Dùng lệnh này là bạn tách rời tên mảng ra khỏi bộ nhớ của nó. Tức là muốn dùng a kế tiếp thì bạn phải ReDim nó lại. Chả hiệu quả chút nào so với ReDim. Nhưng nếu code của bạn gặp vấn đề với lượng bộ nhớ thì Erase là cách hữu hiệu nhất để bảo đảm mảng nhả bộ nhớ ra.

Ghi chú thêm về bộ nhớ: nếu bạn gặp vấn đè với lượng bộ nhớ thì không nên dùng mảng tĩnh. Bởi vì Erase nó chả giúp cho bạn thấu về bộ nhớ. Tuy nhiên nếu vấn đề không đễn nỗi nặng và lý do chính nằm ở mảng chuỗi thì cái nào cũng được. Trong mảng chuỗi, các vị trí phần tử chỉ chứa con trỏ đến chuỗi giá trị.

Úi bác phức tạp thật....
Về vấn đề chính: theo em thì Erase là xóa (không cần google dịch), Dim là định nghĩa biến => Redim là định nghĩa lại biến, mà định nghĩa lại thì nó phải xem cái cũ không tồn tại nghĩa là xóa.
...
Bỏi tôi biết là từ Erase/ReDim dễ bị hiểu lầm cho nên tôi cố tình nói chgo bạn ở bài #10 hỏi.
Ở đây tôi biết chỉ có mình bạn ấy và 1 bạn nữa là có thì giờ nghe chuyện "lý thuyết" của tôi. Những người khác xem trọng "thực hành" hơn.

Và thục hành ra sao tôi không biết chứ về lý thuyết thì hiểu đơn giản như vậy là SAI!
Điển hình nhất: bạn bảo ReDim là định nghĩa lại biến là sai. Chịu khó đọc câu thứ hai của phần trên. Nếu nói đúng thì phải là "lập mảng mới với kích thước mới". Lập mảng khác với định nghĩa mảng.
Khai báo (Dim) là lệnh dẫn trình dịch, xảy ra trước khi code chạy. Sửa mảng (ReDim) là lệnh bình thường, xảy ra khi code chạy.

Hồi nào tôi cứ ngỡ việc phân biệt lệnh dẫn và lệnh chạy là chuyện thực tế. Té ra bà con coi đấy là lý thuyết?

Bổ sung: xin lõi câu tô đậm ở trên tôi viết nhầm. Nhờ bài !#14 tôi mới nhận ra. Xin chỉnh lại như sau:
Mảng động dùng ReDim, mảng tĩnh dùng Erase (có muốn ReDim VBA cũng không cho phép).
 
Lần chỉnh sửa cuối:
Upvote 0
Xem code khai báo. Khi tôi dùng Dim a(1 To 10) thì a được xác định là mảng tĩnh. Khi hai bài kia khai Dim a() thì VBA hiểu là mảng động.
Mảng tĩnh luôn xác định vị trí cố định trong bộ nhớ, và được VBA tạo ngay lúc khai báo. Mảng động chỉ là giành trước tên biến, chưa xác định gì cả (ngoài việc nếu bạn có thêm As kiểu gì đó thì mảng bắt buộc phải là kiểu ấy).

Để trở về trị mặc định (điển hình 0 với kiểu số, "" với kiểu chuỗi,...), mảng động dùng Erase, mảng tĩnh dùng ReDim. Nói cách khác:
1. mảng tĩnh không thể ReDim. Đã tĩnh rồi cón ReDim sửa đổi số cột/dòng khỉ mốc gì nữa.
2. mảng động không thể Erase (không hẳn đúng 100%, xem phần cuối đoạn này sẽ rõ). Dùng lệnh này là bạn tách rời tên mảng ra khỏi bộ nhớ của nó. Tức là muốn dùng a kế tiếp thì bạn phải ReDim nó lại. Chả hiệu quả chút nào so với ReDim. Nhưng nếu code của bạn gặp vấn đề với lượng bộ nhớ thì Erase là cách hữu hiệu nhất để bảo đảm mảng nhả bộ nhớ ra.

Ghi chú thêm về bộ nhớ: nếu bạn gặp vấn đè với lượng bộ nhớ thì không nên dùng mảng tĩnh. Bởi vì Erase nó chả giúp cho bạn thấu về bộ nhớ. Tuy nhiên nếu vấn đề không đễn nỗi nặng và lý do chính nằm ở mảng chuỗi thì cái nào cũng được. Trong mảng chuỗi, các vị trí phần tử chỉ chứa con trỏ đến chuỗi giá trị.


Bỏi tôi biết là từ Erase/ReDim dễ bị hiểu lầm cho nên tôi cố tình nói chgo bạn ở bài #10 hỏi.
Ở đây tôi biết chỉ có mình bạn ấy và 1 bạn nữa là có thì giờ nghe chuyện "lý thuyết" của tôi. Những người khác xem trọng "thực hành" hơn.

Và thục hành ra sao tôi không biết chứ về lý thuyết thì hiểu đơn giản như vậy là SAI!
Điển hình nhất: bạn bảo ReDim là định nghĩa lại biến là sai. Chịu khó đọc câu thứ hai của phần trên. Nếu nói đúng thì phải là "lập mảng mới với kích thước mới". Lập mảng khác với định nghĩa mảng.
Khai báo (Dim) là lệnh dẫn trình dịch, xảy ra trước khi code chạy. Sửa mảng (ReDim) là lệnh bình thường, xảy ra khi code chạy.

Hồi nào tôi cứ ngỡ việc phân biệt lệnh dẫn và lệnh chạy là chuyện thực tế. Té ra bà con coi đấy là lý thuyết?
Em đọc xong và rối tung, cơ bản là do không có cơ bản nên chịu. Em chỉ thấy khi code có array thì y rằng dưới sẽ có redim, và cứ nhớ vậy cho gọn.
Bây giờ bỏ qua bộ nhớ thì nên dùng redim cho chủ động đúng không bác? Em nghĩ bộ nhớ bây giờ nhiều, chắc cũng không cần erase làm gì, code chạy xong nó cũng tự xóa hết biến thì phải (hình như thế).
Trên bác bôi đậm không biết là có ý đồ chiến thuật gì vậy ạ? :wallbash: :wallbash: :wallbash:
 
Upvote 0
Upvote 0
Xin lỗi tôi viết nhầm. Đúng thì phải là:
Mảng động dùng ReDim, mảng tĩnh dùng Erase (có muốn ReDim VBA cũng không cho phép).
Em thì lý thuyết không nhớ được nên phải tóm nó gọn lại.
VD: array kèm redim. for cần false updating... Nói chung là làm cho dễ nhớ, quan điểm "sai thì sửa, chửa thì đẻ". :wallbash: :wallbash: :wallbash:
Có vẻ không hợp lý lắm.

Vẫn đang suy ngẫm, chưa kịp hỏi thì anh đã điều chỉnh lại rồi.
há há há. Văn 5, 6 nên nó lại rất hợp lý.
 
Upvote 0
...VD: array kèm redim. for cần false updating... Nói chung là làm cho dễ nhớ, quan điểm "sai thì sửa, chửa thì đẻ". :wallbash: :wallbash: :wallbash:
Đỏ: tôi có bài viết về lệnh for/next. Nó không hẳn đơn giản như bạn nghĩ.
Xanh: nếu bạn có con gái thì bạn có còn quan niệm ấy không? Có những việc đợi đến mới sửa sai, có những việc đaoịh đến sửa sai thì đã bút sa gà chết.
Chú: tôi hiểu chỗ dỏ, nó liên quan đến chỗ xanh. Từ next là tôi nói trại từ need (không ai Tây bồi êm bằng tôi đâu :p ).
 
Upvote 0
Đỏ: tôi có bài viết về lệnh for/next. Nó không hẳn đơn giản như bạn nghĩ.
Xanh: nếu bạn có con gái thì bạn có còn quan niệm ấy không? Có những việc đợi đến mới sửa sai, có những việc đaoịh đến sửa sai thì đã bút sa gà chết.
Chú: tôi hiểu chỗ dỏ, nó liên quan đến chỗ xanh. Từ next là tôi nói trại từ need (không ai Tây bồi êm bằng tôi đâu :p ).
Tình huống vui vẻ thôi bác.
Nhưng mà có chứ bác, nếu may mắn mà có con gái, rồi nếu đen đen mà nó rơi vào xanh xanh thì vẫn phải cho xanh chứ không cho phá được. :(:(:(
Chỗ đỏ thì thực ra em vắn tắt cho gọn, chứ lên google tìm đúng dòng đấy thì lâu lắm. :wallbash::wallbash::wallbash:
 
Upvote 0
...
Nhưng mà có chứ bác, nếu may mắn mà có con gái, rồi nếu đen đen mà nó rơi vào xanh xanh thì vẫn phải cho xanh chứ không cho phá được. :(:(:(
...
Tôi có nói chuyện phá hay để đâu - đó là chính kiến về xã hội. Mà nói chính kiến thì cả đời còn chưa hết.
Nếu bạn chịu khói suy nghĩ thì đã thấy tôi nói về phòng bịnh hơn chữa bịnh mà. Chữa cách nào thì tôi chưa nói.

Chú: bạn có lẽ đơn giản hóa chình kiến người khác. Đơn giản hóa mình là máu lạnh, đơn giản hóa người khác là chủ quan.
Quan điểm của tôi là tôi thích để rồi nuôi. Nhưng tôi vẫn ủng hộ phá với điều kiện.
Ở Âu Mẽo, tình trạng xã hội tương đối tốt, điều kiện của tôi khắt khe hơn. Bởi vì người ta đủ điều kiện để cân nhắc, và có xã hội để giúp đỡ, cho nên việc cứ nêu ra vài lý rồi phá là hơi vô trách nhiệm.
Nhưng ở VN thì phải xét:
1. Người ta có đủ điều kiện kinh tế? Nhà nghèo sặc gạch mà cứ bảo "trời snh voi sinh cỏ" là nói tầm bậy.
2. Người đàn bà bị cưỡng ép - trực tiếp hay gián tiếp. Phải xét lại chuyện đẻ và nuôi có ảnh hưởng đến tnh thần cả mẹ lẫn con. Tôi đã từng biết có nhiều nhà coi phá là tội lỗi, nhưng có "thai hoang" là sỉ nhục, cho dù lỗi là của cái thằng chó đẻ kia chứ cả mẹ lẫn con chả ai tội tình gì.chả phải lỗi ai hết. Điều này ở Âu Mẽo nó dễ vì nó có điều kiện đi bác sĩ tâm lý.
3. Thai nhi khuyết tật. Một nhà bình thường có đủ tài chính và trình độ để theo dõi thường xuyên chăng? Ở mức nào thì giải quyết thế nào?
Chung quy thì chuẩn bị tinh thần trước cho mọi tình huống có phải hơn không?

Chú 2: cái phần chú trên nó có liên hệ gián tiếp với lý luận "phòng bịnh hơn chữa bịnh".
Có những người ra sai tùm lum rồi phát hoảng lên. Bình tĩnh nhận định tình huống mới quan trọng. Và để đạt bình tĩnh thì không gì hơn chuẩn bị trước.
 
Lần chỉnh sửa cuối:
Upvote 0
2. mảng động không thể Erase (không hẳn đúng 100%, xem phần cuối đoạn này sẽ rõ). Dùng lệnh này là bạn tách rời tên mảng ra khỏi bộ nhớ của nó. Tức là muốn dùng a kế tiếp thì bạn phải ReDim nó lại. Chả hiệu quả chút nào so với ReDim. Nhưng nếu code của bạn gặp vấn đề với lượng bộ nhớ thì Erase là cách hữu hiệu nhất để bảo đảm mảng nhả bộ nhớ ra.
Sau khi đọc đoạn này, Chợt nhận ra bản thân cháu cũng đang mập mờ chỗ này.
1671463571980.png
Rõ ràng cũng dùng kiểu này mà lơ ngơ lẫn cả 2 cái luôn.
 
Upvote 0
Web KT

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

Back
Top Bottom