tanthanh94
Thành viên mới

- Tham gia
- 24/8/14
- Bài viết
- 46
- Được thích
- 3
Hiện tại file sử dụng hàm sumif rất nhiều dòng
Nay nhờ các Anh viết code để giảm dung lượng file
Public Sub GPE()
Dim Dic As Object, sArr(), dArr(), I As Long, Tem As String
Set Dic = CreateObject("Scripting.Dictionary")
sArr = Range([B5], [B5].End(xlDown)).Resize(, 5).Value2
ReDim dArr(1 To UBound(sArr, 1), 1 To 1)
For I = 1 To UBound(sArr, 1)
Tem = sArr(I, 1)
If Not Dic.Exists(Tem) Then
Dic.Add Tem, sArr(I, 5)
Else
Dic.Item(Tem) = Dic.Item(Tem) + sArr(I, 5)
End If
Next I
For I = 1 To UBound(sArr, 1)
dArr(I, 1) = Dic.Item(sArr(I, 1))
Next I
[H5].Resize(I - 1) = dArr
Set Dic = Nothing
End Sub
Do file của em có 13 sheet dùng công thức như vậy nên cần code để giảm dung lượng fileSUMIF với 5000 dòng chưa phải là "oải".
Muốn Sub thì tặng bạn cái này.
PHP:Public Sub GPE() Dim Dic As Object, sArr(), dArr(), I As Long, Tem As String Set Dic = CreateObject("Scripting.Dictionary") sArr = Range([B5], [B5].End(xlDown)).Resize(, 5).Value2 ReDim dArr(1 To UBound(sArr, 1), 1 To 1) For I = 1 To UBound(sArr, 1) Tem = sArr(I, 1) If Not Dic.Exists(Tem) Then Dic.Add Tem, sArr(I, 5) Else Dic.Item(Tem) = Dic.Item(Tem) + sArr(I, 5) End If Next I For I = 1 To UBound(sArr, 1) dArr(I, 1) = Dic.Item(sArr(I, 1)) Next I [H5].Resize(I - 1) = dArr Set Dic = Nothing End Sub
SUMIF với 5000 dòng chưa phải là "oải".
Muốn Sub thì tặng bạn cái này.
PHP:Public Sub GPE() Dim Dic As Object, sArr(), dArr(), I As Long, Tem As String Set Dic = CreateObject("Scripting.Dictionary") sArr = Range([B5], [B5].End(xlDown)).Resize(, 5).Value2 ReDim dArr(1 To UBound(sArr, 1), 1 To 1) For I = 1 To UBound(sArr, 1) Tem = sArr(I, 1) If Not Dic.Exists(Tem) Then Dic.Add Tem, sArr(I, 5) Else Dic.Item(Tem) = Dic.Item(Tem) + sArr(I, 5) End If Next I For I = 1 To UBound(sArr, 1) dArr(I, 1) = Dic.Item(sArr(I, 1)) Next I [H5].Resize(I - 1) = dArr Set Dic = Nothing End Sub
Application.WorksheetFunction.SumIf
Cải thiện hơn đó bạn, khi đó ngoài sheet chỉ là các số CHẾT, ko phải là công thức nên Excel ko tính toán khi có sự thay đổi nữa.Xin hỏi em dùngtrong VBA có cải thiện tốt hơn khi dùng công thức ngoài sheets khôngPHP:Application.WorksheetFunction.SumIf
Sau khi chạy code xong, việc cải thiện nó nằm ở chỗ: Trên bảng tính không còn công thức nữa ---> Không còn gì để tính toán nữa ---> Dẫn đến bảng tính sẽ nhanhXin hỏi em dùngtrong VBA có cải thiện tốt hơn khi dùng công thức ngoài sheets khôngPHP:Application.WorksheetFunction.SumIf
SUMIF với 5000 dòng chưa phải là "oải".
Muốn Sub thì tặng bạn cái này.
PHP:Public Sub GPE() Dim Dic As Object, sArr(), dArr(), I As Long, Tem As String Set Dic = CreateObject("Scripting.Dictionary") sArr = Range([B5], [B5].End(xlDown)).Resize(, 5).Value2 ReDim dArr(1 To UBound(sArr, 1), 1 To 1) For I = 1 To UBound(sArr, 1) Tem = sArr(I, 1) If Not Dic.Exists(Tem) Then Dic.Add Tem, sArr(I, 5) Else Dic.Item(Tem) = Dic.Item(Tem) + sArr(I, 5) End If Next I For I = 1 To UBound(sArr, 1) dArr(I, 1) = Dic.Item(sArr(I, 1)) Next I [H5].Resize(I - 1) = dArr Set Dic = Nothing End Sub
Bên trên khai báo "Tem as String"Anh Ba Tê ơi, sao tôi chạy thử code của anh và thay dữ liệu A, B C... thành ngày /tháng/ năm thì nó chỉ ra giá trị 0 nhỉ. Bài toán của tôi là cộng tự động các giá trị nếu cùng ngày. Ví dụ ngày 20/11/2017 cùng phát sinh 200 và dòng khác 20/11/2017 phát sinh giá trị 300 thì giá trị tổng cộng phải là 500. Tôi thử khai báo sArr và dArr là kiểu date nhưng không được. Chân thành cảm ơn anh.
Bên trên khai báo "Tem as String"
Bạn chỉ cần thay bằng "Tem as Variant" hoặc bỏ "as String" là được.
1/ Code chạy từ B5 xuống tới khi kết thúc dữ liệu cuối cùng, giống như kiểu bạn nhấn Ctrl+ Down, nếu từ B5 trờ xuống k có dữ liệu thì nó sẽ chạy tới ô cuối trong sheet cho nên kết quả sẽ trả về giống như bạn thấy.Cảm ơn a Ba Tê rất nhiều ạ, tuy nhiên tôi lại gặp phải 1 trường hợp oái ăm và có thêm 3 câu hỏi, mong anh chỉ giáo cho người mới tìm hiểu VBA như tôi:
1. Khi bỏ "as string" hoặc khai báo thành Variant như anh thì gặp lỗi: "khi tôi xóa hết dữ liệu ở cột B thì chạy code nó tự cộng tổng thành giá trị 2380 tất cả các dòng từ H5 đến dòng cuối cùng của cột H".
2. Nếu bây giờ bài toán của tôi phát sinh thêm việc: tôi muốn VBA tự động lookup những số liệu có ngày tháng mà sau khi tính tổng như sumif ở cột H thì đưa lên tương ứng ngày tháng có đã ghi sẵn hàng ngang ở hàng 2 (Điền vào hàng 3 hoặc hàng tương ứng bất kỳ dưới hàng 2 có mã tên giống mã tên cột H)thì sẽ viết code như thế nào anh nhỉ?
3: Nếu tại ô B2 tôi điền tay là 1 ngày bất kỳ thì từ ô C2 đến ô CZX2 tự động điền các ngày tiếp theo liên tiếp với ngày đã điền, sau đó lookup giá trị đã được sumif ở cột H tương ứng với ngày trên hàng 3 (tính từ ô B3). Mục hỏi 2 và 3 tôi đã làm đc công tác này bằng công thức hàm nhưng file có 30 sheet dữ liệu thì rất nặng nên muốn dùng VBA cho nhẹ hơn.
4: Nếu tôi thay ngược lại cột F (từ F5) là ngày tháng, cột B (Từ B5) là khối lượng thì phải viết code đổi lại thế nào để vẫn tính được?
Trân trọng cảm ơn phản hồi của a Ba Tê và các anh chị khác góp ý. (Vui lòng xem file đính kèm)
Bạn thử.Mình đang đau đầu với code VBA để thay thế hàm sumif. Dử liệu chứa vùng điều kiện và vùng cần tính tổng lấy từ Sheets("BK_NX") > kết quả có chứa điều kiện mình cần trên Sheets("M_SAP").
>>> Bạn nào có code hay cho mình tham khảo với nhé
Sub tinhtong()
Dim arr, i As Long, j As Long, lr As Long, dic As Object, dk As String, a As Long, kq() As Double, lr1 As Long
Set dic = CreateObject("scripting.dictionary")
With Sheets("M_sap")
lr = .Range("B" & Rows.Count).End(xlUp).Row
If lr < 5 Then Exit Sub
arr = .Range("B5:C" & lr).Value
ReDim kq(1 To UBound(arr), 1 To 3)
For i = 1 To UBound(arr)
dk = arr(i, 1)
dic.Item(dk) = i
Next i
End With
With Sheets("bk_nx")
lr1 = .Range("H" & Rows.Count).End(xlUp).Row
arr = .Range("H6:K" & lr1).Value
For i = 1 To UBound(arr)
dk = arr(i, 1)
a = dic.Item(dk)
If a Then
kq(a, 1) = kq(a, 1) + arr(i, 3)
kq(a, 2) = kq(a, 2) + arr(i, 4)
kq(a, 3) = kq(a, 1) - kq(a, 2)
End If
Next i
End With
With Sheets("M_sap")
.Range("E5:G" & lr).Value = kq
End With
End Sub
Thật tuyệt vời. Cảm ơn Bạn nhiều nhiều nhé.Bạn thử.
Mã:Sub tinhtong() Dim arr, i As Long, j As Long, lr As Long, dic As Object, dk As String, a As Long, kq() As Double, lr1 As Long Set dic = CreateObject("scripting.dictionary") With Sheets("M_sap") lr = .Range("B" & Rows.Count).End(xlUp).Row If lr < 5 Then Exit Sub arr = .Range("B5:C" & lr).Value ReDim kq(1 To UBound(arr), 1 To 3) For i = 1 To UBound(arr) dk = arr(i, 1) dic.Item(dk) = i Next i End With With Sheets("bk_nx") lr1 = .Range("H" & Rows.Count).End(xlUp).Row arr = .Range("H6:K" & lr1).Value For i = 1 To UBound(arr) dk = arr(i, 1) a = dic.Item(dk) If a Then kq(a, 1) = kq(a, 1) + arr(i, 3) kq(a, 2) = kq(a, 2) + arr(i, 4) kq(a, 3) = kq(a, 1) - kq(a, 2) End If Next i End With With Sheets("M_sap") .Range("E5:G" & lr).Value = kq End With End Sub
Mình không rành về VBA nên lên đây nhờ các bạn giúp đỡ về code thay thế hàm sumifs. Mình có gửi File đính kèm, trong File mình đang dùng công thức. Chân thành cảm ơn các bạn!
Cho mình hỏi nếu bài này mà chỉ muốn điền kết quả vào dòng đầu tiên của điều kiện thì sửa lại như nào (kiểu như trong ảnh)SUMIF với 5000 dòng chưa phải là "oải".
Muốn Sub thì tặng bạn cái này.
PHP:Public Sub GPE() Dim Dic As Object, sArr(), dArr(), I As Long, Tem As String Set Dic = CreateObject("Scripting.Dictionary") sArr = Range([B5], [B5].End(xlDown)).Resize(, 5).Value2 ReDim dArr(1 To UBound(sArr, 1), 1 To 1) For I = 1 To UBound(sArr, 1) Tem = sArr(I, 1) If Not Dic.Exists(Tem) Then Dic.Add Tem, sArr(I, 5) Else Dic.Item(Tem) = Dic.Item(Tem) + sArr(I, 5) End If Next I For I = 1 To UBound(sArr, 1) dArr(I, 1) = Dic.Item(sArr(I, 1)) Next I [H5].Resize(I - 1) = dArr Set Dic = Nothing End Sub
Bạn đưa file "giống thật" lên đi, rồi nêu rõ yêu cầu, vài dòng kết quả mẫu.Cho mình hỏi nếu bài này mà chỉ muốn điền kết quả vào dòng đầu tiên của điều kiện thì sửa lại như nào (kiểu như trong ảnh)
View attachment 237172
Sub Sum_data_manual()
Dim SumArr(), Sarr()
Dim i As Long, j As Long, l As Long, SLBan As Double, SLTralai As Double, TongBan As Double
Dim SumLr As Long, SumLcol As Long, SLr As Long, SLcol As Long, TG As Double, TongTraLai As Double
TG = Timer()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
SumLr = Sheet1.Range("F" & Rows.Count).End(xlUp).Row
SumLcol = Sheet1.Cells(11, Columns.Count).End(xlToLeft).Column
SumArr = Sheet1.Range("A8").Resize(SumLr - 8 + 1, SumLcol - 1 + 1) ' tu A8
SLr = Sheet2.Range("A" & Rows.Count).End(xlUp).Row
SLcol = Sheet2.Cells(8, Columns.Count).End(xlToLeft).Column
Sarr = Sheet2.Range("A8").Resize(SLr - 8 + 1, SLcol - 1 + 1) ' tu A8
For i = 5 To UBound(SumArr, 1)
If SumArr(i, 1) = Empty And SumArr(i, 6) <> "" Then
For j = UBound(SumArr, 2) To 17 Step -3
For l = 2 To UBound(Sarr, 1)
If SumArr(i, 6) = Sarr(l, 5) And SumArr(1, j) = Sarr(l, 3) Then
If SumArr(4, j) = "3=1-2" Then
SLTralai = SumArr(i, j - 1) + Sarr(l, 16)
SumArr(i, j - 1) = Round(SLTralai, 2)
SLBan = SumArr(i, j - 2) + Sarr(l, 7)
SumArr(i, j - 2) = Round(SLBan, 2)
SumArr(i, j) = Round(SLBan - SLTralai, 2)
SLBan = 0: SLTralai = 0
End If
End If
Next l
Next j
End If
Next i
Sheet1.Range("A8").Resize(SumLr - 8 + 1, SumLcol - 1 + 1) = SumArr
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
MsgBox "Done " & Round(Timer() - TG, 2)
End Sub
Trước bạn có giúp viết code để phân bổ nên mình dựa vào đấy để lấy kết quả là tính tổng nhiều điều kiện thôi, nhưng nó ghi ra kết quả ở tất cả các dòng giống như trong bài này nên mình mới vào hỏi cách để ghi ra dữ liệu ở dòng đầu tiên, nếu rảnh bạn có thể xem lại giúp mình chi tiết mình ghi ở trong file rồiBạn đưa file "giống thật" lên đi, rồi nêu rõ yêu cầu, vài dòng kết quả mẫu.
Trong code tôi gán dữ liệu vào cột S, bạn chỉnh lại vào cột nào tùy ý.Trước bạn có giúp viết code để phân bổ nên mình dựa vào đấy để lấy kết quả là tính tổng nhiều điều kiện thôi, nhưng nó ghi ra kết quả ở tất cả các dòng giống như trong bài này nên mình mới vào hỏi cách để ghi ra dữ liệu ở dòng đầu tiên, nếu rảnh bạn có thể xem lại giúp mình chi tiết mình ghi ở trong file rồi
Public Sub GPE()
Dim sArr(), dArr(), I As Long, R As Long, Tem As String, Rws As Long
sArr = Range("A8", Range("A8").End(xlDown)).Resize(, 13).Value
R = UBound(sArr)
ReDim dArr(1 To R, 1 To 1)
With CreateObject("Scripting.Dictionary")
For I = 1 To R
Tem = sArr(I, 1) & "#" & sArr(I, 2) & "#" & sArr(I, 4) & "#" & sArr(I, 5)
If Not .Exists(Tem) Then
.Item(Tem) = I
dArr(I, 1) = sArr(I, 11)
Else
Rws = .Item(Tem)
dArr(Rws, 1) = dArr(Rws, 1) + sArr(I, 11)
End If
Next I
End With
Range("S8").Resize(R) = dArr
End Sub
Trước bạn có giúp viết code để phân bổ nên mình dựa vào đấy để lấy kết quả là tính tổng nhiều điều kiện thôi, nhưng nó ghi ra kết quả ở tất cả các dòng giống như trong bài này nên mình mới vào hỏi cách để ghi ra dữ liệu ở dòng đầu tiên, nếu rảnh bạn có thể xem lại giúp mình chi tiết mình ghi ở trong file rồi
MaNV | congviec | ca | Sum of Diemluong | Cột phụ lấy max | Cột kết quả |
606 | congviec2 | 3 | 60.625 | ||
647 | congviec2 | 3 | 37.30769231 | ||
661 | congviec2 | 3 | 39.58333333 | ||
853 | congviec2 | 3 | 60.625 | ||
939 | congviec1 | 3 | 72.71428571 | ||
1,120 | congviec2 | 3 | 158.3333333 | ||
1,124 | congviec1 | 3 | 56.55555556 | ||
3,901 | congviec2 | 3 | 37.30769231 | ||
3,913 | congviec1 | 3 | 84.83333333 |
Có lẽ do bạn lâu quá chưa trở lại diễn đàn (hoặc bạn mượn tên của mọt người cũ) nên không biết đường lối giải quyết của hầu nhết ngừoi ở đây:Mình diễn ý lại đúng ý bạn không nhé:
Bạn cần kết quả của những nhân viên có làm ca 3 và đảm bảo những nhân viên này không vượt max (dữ liệu mẫu của bạn không đầy đủ!). Nếu bài toán chỉ như vậy thì theo mình để nhanh chỉ cần như sau: Tonghop --> Pivot + filter ca3 + field công việc --> tạo cột max; cột kq so sánh tổng điểm + max --> Pivot lần nữa hoặc dùng trực tiếp { 1 }
Bài toán hiện tại của bạn thực sự viết code càng khó cho bạn quản lý sau này { 2 }. Viết code cho vụ này thì phí lắm và bạn cũng chưa học được việc khai thác hết sức mạnh add-in của Excel { 3 }
Chuẩn rồi bạn bài này mình muốn dùng pivot để lấy dữ liệu từ 2 bảng ra, mình không biết pivot kiểu j ra được cái cột max đấy, mình đang làm thì pivot ra cột điểm lương xong vlookup ra bảng phụ để điền cột max (nó có nhược điểm hàng ngày số mã nv thay đổi nên dòng tổng thay đổi dẫn đến phải sửa lại bảng phụ) mình có đăng bài rồi nhưng ko đc hướng dẫn nên buộc phải nghĩ cách điền cái tổng ra trước vlookup theo cái đấy rồi mới pivotMình diễn ý lại đúng ý bạn không nhé:
Bạn cần kết quả của những nhân viên có làm ca 3 và đảm bảo những nhân viên này không vượt max (dữ liệu mẫu của bạn không đầy đủ!). Nếu bài toán chỉ như vậy thì theo mình để nhanh chỉ cần như sau: Tonghop --> Pivot + filter ca3 + field công việc --> tạo cột max; cột kq so sánh tổng điểm + max --> Pivot lần nữa hoặc dùng trực tiếp
Bài toán hiện tại của bạn thực sự viết code càng khó cho bạn quản lý sau này. Viết code cho vụ này thì phí lắm và bạn cũng chưa học được việc khai thác hết sức mạnh add-in của Excel
MaNV congviec ca Sum of Diemluong Cột phụ lấy max Cột kết quả 606 congviec2 3 60.625647 congviec2 3 37.30769231661 congviec2 3 39.58333333853 congviec2 3 60.625939 congviec1 3 72.714285711,120 congviec2 3 158.33333331,124 congviec1 3 56.555555563,901 congviec2 3 37.307692313,913 congviec1 3 84.83333333
Có lẽ do bạn lâu quá chưa trở lại diễn đàn (hoặc bạn mượn tên của mọt người cũ) nên không biết đường lối giải quyết của hầu nhết ngừoi ở đây:
{ 1 } Cái bạn đề nghị cần khá nhiều động tác. Mà dân hỏi bài ở đây chỉ muốn 1 động tác là bấm nút. Nhiều người thẳng thừng phân bày là nhiều đọng tác thì "dễ bị nhầm lẫn". Muốn gọi đó là tinh thần hưởng ứng kỹn nghệ tiên tiến hay do lười quen ỷ lại tuỳ thuộc vào quan điểm của bạn. Nhưng sự thật là vậy.
{ 2 } Người ta chỉ làm cho xong việc rồi biến đi, để cái "khó quản lý sau này" cho người kế vị. Ở đây bạn gặp trườngn hợp này không ít. Dânn ở đay có nthois quen "yêu cuồng sống vội". Đòi hỏi người ta phải nghĩ đến tương lại là đòi hỏi nhiều quá.
{ 3 } Khia thác sức mạnh của Excel hầu như không cần thiết nếu bạn biết khai thác sức mạnh của GPE.
Tôi có đồng ý với bạn hay không hoàn toàn vôn nghĩa ở đây.Vấn đề giải pháp là trong tình huống cụ thể mình đưa ra đỡ tốn sức nhất, nhanh nhất. Bạn đồng ý như vậy không? ...
Cách dễ nhất, nhanh nất là nhờ ngừoi khác viết code giùm mình rồi bấm nút chạy.... Chính vì vậy theo mình đưa ra cách thức dễ nhất, nhanh nhất để thực hiện.
Mô hình là tiếng Ma rốc ở diễn đàn này....Để có thể giải quyết gốc với một nút bấm mà không có mô hình + viết macros hoặc VBA lai thì sao thực hiện được. Đó là chưa kể bug lỗi..
Thử làm thống kê xem có bao nhiêu người dùng "rút ra cho mình cái gì đó".... Và người dùng tham khảo còn rút ra cho mình cái gì đó chứ giải quyết một lần thì lần sau cũng sẽ tiếp tục hỏi vấn đề tương đương thôi.