vanlinh_2904
Thành viên hoạt động



- Tham gia
- 20/10/12
- Bài viết
- 117
- Được thích
- 3
Chào các Anh/Chị
Em nhờ anh chị viết giúp em VBA để mỗi khi nhập liệu nếu mỗi nhân viên trong cùng 1 ngày có số tiền chi vượt quá mức quy định thì báo lỗi.
Em cảm ơn các anh/chị.
Data Valiadation rất hiệu quả.Cảm ơn 2 bạn Vũ Kim Hiếu và Phuocam, Data Validation thì mình đã có rồi, bạn nào có code VBA thì cho mình xin để thay cho Data Validation nhé.
Do Data Valiadation thì khi thực hiện copy thì nó lại không báo lỗi, chỉ có đánh trực tiếp mới báo lỗi nên mình tìm VBA, bạn có cách nào giúp mình với ạ.Data Valiadation rất hiệu quả.
Bạn chỉ code VBA kkhi bạn có nhiều lý do cần uyển chuyển hơn.
Trường hợp này bạn phải là người viết code, và chỉ hỏi một vài chỗ bí.
Hỏi người ta làm từ a đến z thì chả lợi gì hơn dùng công cụ có sẵn của Excel cả.
Ngài Bill đã làm gì để bạn phật ý không dùng công cụ của ông ta mà bạn lại muốn sử dụng code VBA?Do Data Valiadation thì khi thực hiện copy thì nó lại không báo lỗi, chỉ có đánh trực tiếp mới báo lỗi nên mình tìm VBA, bạn có cách nào giúp mình với ạ.
1. Copy cũng không kích hoạt sự kiện (VBA). Những chắp vá đều chỉ có hiệu quả tương đối.Do Data Valiadation thì khi thực hiện copy thì nó lại không báo lỗi, chỉ có đánh trực tiếp mới báo lỗi nên mình tìm VBA, bạn có cách nào giúp mình với ạ.
Cảm ơn bạn nhiều nhéNgài Bill đã làm gì để bạn phật ý không dùng công cụ của ông ta mà bạn lại muốn sử dụng code VBA?
Xem file thử xem, hy vọng đúng ý.
Nhờ bạn sửa lại code giúp mình khi copy và dán vào cột B thì vẫn thực hiện được thông báo. Cảm ơn bạn nhiềuNgài Bill đã làm gì để bạn phật ý không dùng công cụ của ông ta mà bạn lại muốn sử dụng code VBA?
Xem file thử xem, hy vọng đúng ý.
Hỏi cụ thể chút về cách nhập liệu của bạn, tức là bạn có cột ngày và số lượng sẵn từ trước? Chỉ nhập tên nhân viên thôi phải không? Hay là cứ mỗi dòng nhập tên NV xong nhập ngày và số lượng?Nhờ bạn sửa lại code giúp mình khi copy và dán vào cột B thì vẫn thực hiện được thông báo. Cảm ơn bạn nhiều
Nhập cả tên nhân viên ngày và số lượng nữa bạn, hiện thông báo và xoá giá trị nhập sai bạn nhé, cảm ơn bạn.Hỏi cụ thể chút về cách nhập liệu của bạn, tức là bạn có cột ngày và số lượng sẵn từ trước? Chỉ nhập tên nhân viên thôi phải không? Hay là cứ mỗi dòng nhập tên NV xong nhập ngày và số lượng?
Còn nữa, nhập xong chỉ cần hiện thông báo thôi hay là hiện thông báo xong và xóa giá trị vừa nhập vào?
Ngồi viết thử một khúc thì nhận ra có nhiều vấn đề:Nhập cả tên nhân viên ngày và số lượng nữa bạn, hiện thông báo và xoá giá trị nhập sai bạn nhé, cảm ơn bạn.
Thử xem.Nhờ bạn sửa lại code giúp mình khi copy và dán vào cột B thì vẫn thực hiện được thông báo. Cảm ơn bạn nhiều
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("B5:B100000")) Is Nothing Then
On Error GoTo Thoat
Call HanCheChi
If IsArray(Targer) = False Then
Set Rng = Target
k = Rng.Rows.Count
Set eRng = Rng.Resize(k, 3)
For j = 1 To k
For i = 1 To UBound(Res)
If eRng(j, 1) = Res(i, 1) And eRng(j, 2) = Res(i, 2) And Res(i, 3) > Sheet1.[H3] Then
MsgBox "Ngày " & eRng(j, 2) & " Nhân viên " & eRng(j, 1) & " đa chi quá han mưc", vbCritical, " THÔNG BÁO"
eRng(j, 3) = ""
End If
Next i
Next j
End If
End If
Thoat:
End Sub
Sự kiện chỉ bắt mỗi cột B làm sao mà được bác. Người ta trả lời thế này mà:Thử xem.
Chỉnh lại code.
P/s: Chỉ bắt sữ kiện khi thay đổi các ô ở cột B. Nếu đã chi quá sẽ xóa ô tương ứng ở cột DMã:Private Sub Worksheet_Change(ByVal Target As Range) If Not Intersect(Target, Range("B5:B100000")) Is Nothing Then On Error GoTo Thoat Call HanCheChi If IsArray(Targer) = False Then Set Rng = Target k = Rng.Rows.Count Set eRng = Rng.Resize(k, 3) For j = 1 To k For i = 1 To UBound(Res) If eRng(j, 1) = Res(i, 1) And eRng(j, 2) = Res(i, 2) And Res(i, 3) > Sheet1.[H3] Then MsgBox "Ngày " & eRng(j, 2) & " Nhân viên " & eRng(j, 1) & " đa chi quá han mưc", vbCritical, " THÔNG BÁO" eRng(j, 3) = "" End If Next i Next j End If End If Thoat: End Sub
Nhập tên xong, chưa có tiền thì mọi sự vẫn tốt đẹp. Nhưng đến khi nhập tiền vào, nếu vượt thì code có bắt sự kiện này nữa đâuNhập cả tên nhân viên ngày và số lượng nữa bạn, hiện thông báo và xoá giá trị nhập sai bạn nhé,
Tôi nghĩ rằng 1 thành viên tham gia diễn đàn từ năm 2012 như chủ thớt chắc có đủ kiến thức để tùy chỉnh theo ý mình. Nếu mà làm nữa thì họ học được gì?Sự kiện chỉ bắt mỗi cột B làm sao mà được bác. Người ta trả lời thế này mà:
Nhập tên xong, chưa có tiền thì mọi sự vẫn tốt đẹp. Nhưng đến khi nhập tiền vào, nếu vượt thì code có bắt sự kiện này nữa đâu
1.Trong vùng paste mà có nhân viên không thỏa mãn điều kiện thì xóa những nhân viên không thỏa mãn điều kiện đó ở vùng paste, những nhân viên trong vùng paste thỏa mãn điều kiện thì giữ lại.Ngồi viết thử một khúc thì nhận ra có nhiều vấn đề:
1/ Trường hợp nhập liệu từng dòng thì dễ rồi
2/ Trường hợp copy paste:
- Nếu vùng paste có nhân viên thỏa mã điều kiện, có nhân viên không thì thông báo thế nào? ( Đã nghĩ là sẽ thông báo những nhân viên nào không phù hợp và xóa những NV đó (*), giữ lại những nhân viên thỏa mãn)
- Phần (*) của ý trên: Giả sử Nhân viên A (trong vùng paste) có nhiều dòng (giả sử 5 dòng), nếu tổng trên xuống 4 dòng thì thỏa mãn, nhưng sang đến dòng thứ 5 thì nó vượt. Vậy chỗ này xóa hết tất cả hay xóa dòng dư (**)
- Phần (**) của ý trên: Nếu xóa dòng dư thì lấy dưới lên hay thế nào? Nhân viên A: Dòng 1 = 900.000 , Dòng 2 đến dòng 5 chỉ 200.000 mỗi dòng. Vậy tính dưới lên thì phải xóa từ 2 tới 5. Nhưng nếu xác định thỏa mãn càng nhiều càng tốt thì lại phải xóa dòng 1
Còn nếu chỉ nêu ra vùng đó có chứa nhân viên nào đó không thỏa mãn điều kiện và xóa hết tất cả dữ liệu của vùng paste thì đơn giản hơn
Có thể là học thêm được tính kiên nhẫn và sẽ nhờ làm tiếp đến khi đạt mong muốn.Tôi nghĩ rằng 1 thành viên tham gia diễn đàn từ năm 2012 như chủ thớt chắc có đủ kiến thức để tùy chỉnh theo ý mình. Nếu mà làm nữa thì họ học được gì?
Vẫn còn đơn giản chán vì bạn vẫn chưa xét hết các trường hợp.Ngồi viết thử một khúc thì nhận ra có nhiều vấn đề:
1/ Trường hợp nhập liệu từng dòng thì dễ rồi
2/ Trường hợp copy paste:
- Nếu vùng paste có nhân viên thỏa mã điều kiện, có nhân viên không thì thông báo thế nào? ( Đã nghĩ là sẽ thông báo những nhân viên nào không phù hợp và xóa những NV đó (*), giữ lại những nhân viên thỏa mãn)
- Phần (*) của ý trên: Giả sử Nhân viên A (trong vùng paste) có nhiều dòng (giả sử 5 dòng), nếu tổng trên xuống 4 dòng thì thỏa mãn, nhưng sang đến dòng thứ 5 thì nó vượt. Vậy chỗ này xóa hết tất cả hay xóa dòng dư (**)
- Phần (**) của ý trên: Nếu xóa dòng dư thì lấy dưới lên hay thế nào? Nhân viên A: Dòng 1 = 900.000 , Dòng 2 đến dòng 5 chỉ 200.000 mỗi dòng. Vậy tính dưới lên thì phải xóa từ 2 tới 5. Nhưng nếu xác định thỏa mãn càng nhiều càng tốt thì lại phải xóa dòng 1
Còn nếu chỉ nêu ra vùng đó có chứa nhân viên nào đó không thỏa mãn điều kiện và xóa hết tất cả dữ liệu của vùng paste thì đơn giản hơn
1. Dòng 7-11 ( ngoài vùng dán) sẽ không bị xóa, chỉ xét xóa từ 4-6 ( trong vùng dán) thứ tự xét lần lượt dòng 4 đến dòng 6 :Vẫn còn đơn giản chán vì bạn vẫn chưa xét hết các trường hợp.
Nếu đọc bài cuối của thớt thì thấy là dữ liệu được nhập / dán không theo thứ tự. Tức tôi hiểu (có thể hiểu sai) là vd. nhân viên A có 5 dòng từ 7 đến 11 đều thỏa điều kiện, tức TỐT. Bây giờ người ta dán 3 dòng cũng của nhân viên A vào dòng 4-6, cũng TỐT cả. Vậy 4-6 giữ lại. Nhưng do có 4-6 nên 7-11 không còn TỐT nữa. Vậy phải xóa 7-11? Hoặc chỉ xóa 9-11 vì 7-8 may mắn vẫn còn TÔT?
Thì tôi viết rõ mà, chỉ là đoán mò thôi. Bạn có mô tả hết các trường hợp đâu mà muốn người khác viết code. Không có bài của tôi thì riêng việc thống nhất cách xử lý cũng phải vài bài nữa. Vì thế tôi không tham gia. Tôi chỉ "giao lưu" với người khác thôi.1. Dòng 7-11 ( ngoài vùng dán) sẽ không bị xóa, chỉ xét xóa từ 4-6 ( trong vùng dán) thứ tự xét lần lượt dòng 4 đến dòng 6 :
- Nếu ( dòng 4 + ngoài vùng dán) > mức quy định => thì xóa dòng 4, 5, 6;
- Nếu (dòng 4 + ngoài vùng dán ) < mức quy định =>thì xét đến dòng 5, nếu ( dòng 5+ dòng 4 + ngoài vùng dán ) > mức quy định thì xóa dòng 5-6.
2. Số liệu ngoài vùng dán phải cố định không được xóa ( vì xóa thì mức còn lại sau mỗi lần nhập sẽ bị thay đổi liên tục khi đó số liệu sẽ bị xóa liên tục)
Lúc đầu em cũng không để ý, nhưng đến bác nói thì em có cảm giác như là đang giao việc thật. Nhưng thôi em cũng không quan tâm lắm, vì thấy cũng trả lời vào trọng tâm câu hỏi.#17 & #20 là tác giả đang giao nhiệm vụ đó; Các bạn ráng mà làm ra cho xong đi, giời ạ!
Những mong đến #40 thì sẽ hoàn tất mọi iêu cầu!
Chúc các bác có những ngày cuối tuần vui vẻ & tràn đầy năng lượng!
Bạn dán code này vào module sheet1, chạy thử xem có vấn đề gì không:1. Dòng 7-11 ( ngoài vùng dán) sẽ không bị xóa, chỉ xét xóa từ 4-6 ( trong vùng dán) thứ tự xét lần lượt dòng 4 đến dòng 6 :
- Nếu ( dòng 4 + ngoài vùng dán) > mức quy định => thì xóa dòng 4, 5, 6;
- Nếu (dòng 4 + ngoài vùng dán ) < mức quy định =>thì xét đến dòng 5, nếu ( dòng 5+ dòng 4 + ngoài vùng dán ) > mức quy định thì xóa dòng 5-6.
2. Số liệu ngoài vùng dán phải cố định không được xóa ( vì xóa thì mức còn lại sau mỗi lần nhập sẽ bị thay đổi liên tục khi đó số liệu sẽ bị xóa liên tục)
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Not Intersect(Target, Range("B5:D" & Rows.Count)) Is Nothing Then
Static Dic As Object
Dim sArr(), Arr(), Lr&, I&, iKey$, Str$
Const iMax# = 1000000#, N$ = vbNullString
If Dic Is Nothing Then Set Dic = CreateObject("Scripting.Dictionary") Else Dic.RemoveAll
Lr = Cells(Rows.Count, "B").End(xlUp).Row
sArr = Range("B5:D" & Lr).Value2
Arr = Range(Cells(Target.Row, "B"), Cells(Target.Rows(Target.Rows.Count).Row, "D")).Value2
For I = 1 To UBound(sArr)
iKey = sArr(I, 1) & "|" & sArr(I, 2)
Dic(iKey) = Dic(iKey) + sArr(I, 3)
Next
For I = UBound(Arr) To 1 Step -1
iKey = Arr(I, 1) & "|" & Arr(I, 2)
If Dic(iKey) > iMax Then
If InStr(1, Str, Arr(I, 1), 1) = 0 Then
Str = Str & vbNewLine & "NhanVien: " & Arr(I, 1)
End If
Dic(iKey) = Dic(iKey) - Arr(I, 3)
Arr(I, 1) = N: Arr(I, 2) = N: Arr(I, 3) = N
End If
Next
Cells(Target.Row, "B").Resize(UBound(Arr), UBound(Arr, 2)) = Arr
If Len(Str) Then
Str = "Cac ma sau khong thoa man, da xoa: " & Str
MsgBox "Xong! " & Str
End If
End If
Application.EnableEvents = True
End Sub
Mình chạy thấy không có mã nào bị xóa nhưng vẫn luôn hiện thông báo, còn về kết quả thì đúng rồi. Cảm ơn bạn nhé!Lúc đầu em cũng không để ý, nhưng đến bác nói thì em có cảm giác như là đang giao việc thật. Nhưng thôi em cũng không quan tâm lắm, vì thấy cũng trả lời vào trọng tâm câu hỏi.
Bạn dán code này vào module sheet1, chạy thử xem có vấn đề gì không:
Mã:Option Explicit Private Sub Worksheet_Change(ByVal Target As Range) Application.EnableEvents = False If Not Intersect(Target, Range("B5:D" & Rows.Count)) Is Nothing Then Static Dic As Object Dim sArr(), Arr(), Lr&, I&, ShowMsg As Boolean, iKey$, Str$ Const iMax# = 1000000#, N$ = vbNullString If Dic Is Nothing Then Set Dic = CreateObject("Scripting.Dictionary") Else Dic.RemoveAll Lr = Cells(Rows.Count, "B").End(xlUp).Row sArr = Range("B5:D" & Lr).Value2 Arr = Range(Cells(Target.Row, "B"), Cells(Target.Rows(Target.Rows.Count).Row, "D")).Value2 For I = 1 To UBound(sArr) iKey = sArr(I, 1) & "|" & sArr(I, 2) Dic(iKey) = Dic(iKey) + sArr(I, 3) Next For I = UBound(Arr) To 1 Step -1 iKey = Arr(I, 1) & "|" & Arr(I, 2) If Dic(iKey) > iMax Then If InStr(1, Str, Arr(I, 1), 1) = 0 Then Str = Str & vbNewLine & "NhanVien: " & Arr(I, 1) End If Dic(iKey) = Dic(iKey) - Arr(I, 3) Arr(I, 1) = N: Arr(I, 2) = N: Arr(I, 3) = N End If If Arr(I, 1) <> N And Arr(I, 2) <> N And Arr(I, 3) <> N Then ShowMsg = True Next Cells(Target.Row, "B").Resize(UBound(Arr), UBound(Arr, 2)) = Arr If ShowMsg Or Len(Str) Then Str = "Cac ma sau khong thoa man, da xoa: " & Str MsgBox "Xong! " & Str End If End If Application.EnableEvents = True End Sub
Hình như khúc đó tôi nghĩ cái gì không nhớ nữa mới thêm một khúc vào, đã sửa lại code xóa khúc đó nhé!Mình chạy thấy không có mã nào bị xóa nhưng vẫn luôn hiện thông báo, còn về kết quả thì đúng rồi. Cảm ơn bạn nhé!View attachment 280120
Cảm ơn bạn rất nhiều.Hình như khúc đó tôi nghĩ cái gì không nhớ nữa mới thêm một khúc vào, đã sửa lại code xóa khúc đó nhé!