Viết Code cho File check

Liên hệ QC

kimthoa89

Thành viên thường trực
Tham gia
3/11/17
Bài viết
215
Được thích
17
Giới tính
Nữ
Thân gửi anh chị !
Nhờ anh chị viết code cho file, từ cột H - > AQ, mỗi một cột em đã có để công thức ở cột đó,
Vậy rất mong anh chị giúp đỡ, em cảm ơn ạ
1652858948647.png
 

File đính kèm

  • Check duyệt.xlsx
    196.7 KB · Đọc: 22
Thân gửi anh chị !
Nhờ anh chị viết code cho file, từ cột H - > AQ, mỗi một cột em đã có để công thức ở cột đó,
Vậy rất mong anh chị giúp đỡ, em cảm ơn ạ
View attachment 276133
Trong khi chờ các giải pháp cao siêu hơn khác, hay thử xem.
Nhấn vào mặt cười để thưởng thức kết quả.
(dòng bôi màu vàng là dòng để thử, Bạn hãy thay đổi, thêm bớt dữ liệu để test)
 

File đính kèm

  • Check duyệt(Mr KimThoa89).xlsm
    193.9 KB · Đọc: 43
Upvote 0
Đợt này thấy chú hay viết Dic ra riêng 1 sub nhỉ?
Tôi viết thế là kết quả học được anh Ndu anh ấy có nói đại ý là đối vói những bài cần lấy dữ liệu nhiều lần từ dic (như kiểu hàm Vlookup) thì nên viết Add_Dic riêng ra để khi cần lấy dữ liệu (khi có thêm dữ liệu cần phải lấy dữ liệu ở sheet khác) sẽ đỡ phải chạy lại dic. Tôi thấy nhiều bài Chỉ cần chạy dic 1 lần khi mở máy và sau đó cứ lấy từ đó ra. Khi có sự thay đổi ở sheet DanhMuc thì sub Add_dic lại được gọi. Việc này tôi thấy là rất có lợi khi ta code phải test đi test lại nhiều lần.
Còn không thì Ghép chung sub add_dic vào trong 1 sub nào đó cũng được mà.
Không biết áp dụng có phần cứng nhắc ấy có vấn đề gì không? Bạn cho mình xin ý kiến nhé
 
Upvote 0
Tôi viết thế là kết quả học được anh Ndu anh ấy có nói đại ý là đối vói những bài cần lấy dữ liệu nhiều lần từ dic (như kiểu hàm Vlookup) thì nên viết Add_Dic riêng ra để khi cần lấy dữ liệu (khi có thêm dữ liệu cần phải lấy dữ liệu ở sheet khác) sẽ đỡ phải chạy lại dic. Tôi thấy nhiều bài Chỉ cần chạy dic 1 lần khi mở máy và sau đó cứ lấy từ đó ra. Khi có sự thay đổi ở sheet DanhMuc thì sub Add_dic lại được gọi. Việc này tôi thấy là rất có lợi khi ta code phải test đi test lại nhiều lần.
Còn không thì Ghép chung sub add_dic vào trong 1 sub nào đó cũng được mà.
Không biết áp dụng có phần cứng nhắc ấy có vấn đề gì không? Bạn cho mình xin ý kiến nhé
Cháu chỉ thấy thắc mắc thế thôi. Như chú viết và chỉ điểm như vậy cũng có cái hay mà. tự dưng nhìn Dic nó tách riêng 1 sub chưa quen lắm. Hihi
 
Upvote 0
Trong khi chờ các giải pháp cao siêu hơn khác, hay thử xem.
Nhấn vào mặt cười để thưởng thức kết quả.
(dòng bôi màu vàng là dòng để thử, Bạn hãy thay đổi, thêm bớt dữ liệu để test)
được rồi ạ, em cảm ơn anh chị đã giúp đỡ ạ
 
Upvote 0
Tôi viết thế là kết quả học được anh Ndu anh ấy có nói đại ý là đối vói những bài cần lấy dữ liệu nhiều lần từ dic (như kiểu hàm Vlookup) thì nên viết Add_Dic riêng ra để khi cần lấy dữ liệu (khi có thêm dữ liệu cần phải lấy dữ liệu ở sheet khác) sẽ đỡ phải chạy lại dic. Tôi thấy nhiều bài Chỉ cần chạy dic 1 lần khi mở máy và sau đó cứ lấy từ đó ra. Khi có sự thay đổi ở sheet DanhMuc thì sub Add_dic lại được gọi. Việc này tôi thấy là rất có lợi khi ta code phải test đi test lại nhiều lần.
Còn không thì Ghép chung sub add_dic vào trong 1 sub nào đó cũng được mà.
Không biết áp dụng có phần cứng nhắc ấy có vấn đề gì không? Bạn cho mình xin ý kiến nhé
Tôi sử dụng dic khá thành thạo nhưng hiếm khi tách riêng ra như thế này. Dic chỉ cần 1s để nạp dữ liệu. Viết rõ ràng sẽ dễ dàng cho việc sửa code khi cần thiết.
 
Upvote 0
Code chỉ đúng duy nhất 1 trường hợp: Chạy lần đầu và dữ liệu ở Sheet (Công tháng 02) không đổi.

Nếu thêm dữ liệu ở Sheet (Công tháng 02) rồi chạy code lần kế tiếp thì không đúng.
Hên sui thì nhận thấy kết quả sai nếu thay đổi it.Mà code viết kiểu này cứ như đi ngược.Chạy tốn vòng lặp hơn.
 
Upvote 0
Có thể bạn sẽ thích...
Click cell B5, chọn tên trong danh sách...
 

File đính kèm

  • Check duyệt 2.xlsm
    207.1 KB · Đọc: 20
Upvote 0
Cháu chỉ thấy thắc mắc thế thôi. Như chú viết và chỉ điểm như vậy cũng có cái hay mà. tự dưng nhìn Dic nó tách riêng 1 sub chưa quen lắm. Hihi
Tôi sử dụng dic khá thành thạo nhưng hiếm khi tách riêng ra như thế này. Dic chỉ cần 1s để nạp dữ liệu. Viết rõ ràng sẽ dễ dàng cho việc sửa code khi cần thiết.
Code chỉ đúng duy nhất 1 trường hợp: Chạy lần đầu và dữ liệu ở Sheet (Công tháng 02) không đổi.

Nếu thêm dữ liệu ở Sheet (Công tháng 02) rồi chạy code lần kế tiếp thì không đúng.
Hên sui thì nhận thấy kết quả sai nếu thay đổi it.Mà code viết kiểu này cứ như đi ngược.Chạy tốn vòng lặp hơn.
Tôi tin là mọi người đều đã đọc bài này:

http://www.giaiphapexcel.com/Thay Code cho hàm Vlookup() bài #10 và bài #18​

 
Upvote 0
Cháu chỉ thấy thắc mắc thế thôi. Như chú viết và chỉ điểm như vậy cũng có cái hay mà. tự dưng nhìn Dic nó tách riêng 1 sub chưa quen lắm. Hihi
Bạn cóp cái code đó ra đây, cả hàm lẫn code gọi nó, thì có thể tôi sẽ giải thích tại sao nó nên tách riêng.
(tôi lười tải file có macro về rồi mở ra xem code lắm)
 
Upvote 0
Bạn cóp cái code đó ra đây, cả hàm lẫn code gọi nó, thì có thể tôi sẽ giải thích tại sao nó nên tách riêng.
Xin phép chú @HUONGHCKT nhé. Tại muốn nghe và hiểu xem cụ thể cái được và mất nếu tách riêng code của Dic ra nó như thế nào? Có gì chú bỏ qua nhé
@VetMini Nhờ chú chỉ dạy thêm ạ.
Đây là code nạp Dic
Mã:
Option Explicit
Public Result(), Dic As Object

Sub Add_Dic()
Dim i&, j&, t&, Lr&
Dim Arr(), Key
Dim Ws As Worksheet
Set Ws = Sheets("Công tháng 02")
Lr = Ws.Cells(Rows.Count, "B").End(xlUp).Row
If Lr < 2 Then Exit Sub
Arr = Ws.Range("A2:AG" & Lr).Value
Set Dic = CreateObject("Scripting.Dictionary")
ReDim Result(1 To UBound(Arr), 1 To 2)
For i = 1 To UBound(Arr)
    Key = Arr(i, 3) & "#" & Arr(i, 2)
    If Not Dic.exists(Key) Then
        t = t + 1: Dic.Add (Key), t
        Result(t, 1) = Key
        Result(t, 2) = Arr(i, 33)
    End If
Next i
End Sub
Và đây là code sử dụng nó ạ
Mã:
Sub KimThoa89()
Dim i&, j&, t&, Lr&
Dim Arr(), Res(), Temp
Dim Ws As Worksheet

Set Ws = Sheets("Check")
Lr = Ws.Cells(Rows.Count, "B").End(xlUp).Row
If Lr < 2 Then Exit Sub
If Dic Is Nothing Then Add_Dic
Arr = Ws.Range("A1:AN" & Lr).Value
ReDim Res(1 To UBound(Arr), 1 To 34)
Ws.Range("H2:H" & Lr).FormulaR1C1 = _
        "=NETWORKDAYS.INTL(RC[-2],RC[-1],""0000001"",{""2022/1/31"";""2022/2/4""})"
For i = 2 To UBound(Arr)
   'Res(i, 1) = Application.WorksheetFunction.NetworkDays(Arr(i, 6), Arr(i, 7), 1, Holiday1, Holiday2)
   Res(i - 1, 2) = Arr(i, 6)
   Res(i - 1, 3) = Arr(i, 7)
   For j = 13 To 40
        Temp = Arr(i, 2) & "#" & Arr(1, j)
            If Dic.exists(Temp) Then Res(i - 1, j - 8) = Result(Dic.Item(Temp), 2)
   Next j
Next i
Ws.Range("I2").Resize(i - 1, 34) = Res
MsgBox "Xong"
End Sub
Cháu xin lắng nghe và cám ơn trước ạ
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn không cho biết chúng nằm cùng một module hay hai modules riêng. Điều này rất quan trọng đối với code sử dụng biến toàn cục.

Vì code thứ hai không có mấy dòng dẫn compiler (Options,...) cho nên tôi tạm cho là cả chúng cùng trong một module.

Theo code Add_Dic trên thì nó không phải loại code chung chung dùng cho nhiều trường hợp đơn giản. Túm lại, nó chỉ là một đoạn code được tách ra thành sub riêng để có thể sử dụng nhiều lần.
Code chủ yếu là nạp dữ liệu cho biến Dic (toàn cục). Code gọi nó sẽ dùng Dic làm bảng tra.

Lợi điểm của cách code này là không phải lặp lại code nhiều lần nếu cảm thấy cần làm lại bảng tra.

Nhược điểm của cách code này là phải dùng biến toàn cục.
Để tránh dùng biến toàn cục, ta có thể dùng Sub nội (sub chứa trong sub), và gọi nó bằng lệnh GoSub. Tuy nhiên, cách này cũng có nhược điểm của nó.

Trên là cấu trúc code. Bây giờ tôi nói đến chi tiết code (xin lỗi tác giả, tôi cần chỉ dẫn cho người cần học)
(i) biến toàn cục dùng chung trong một module thì đáng lẽ phải khai là Private để tránh động chạm ở module khác.
(ii) nếu muốn khai Public thì nên đặt tên đặc thù một chút để tránh bớt trường hợp nhầm lẫn ở module khác. Tên Result và Dic quá đơn giản, dễ bị nhầm.

Nếu tôi viết code riêng sử dụng đít sần làm bảng tra thì tôi viết thành class module.
 
Upvote 0
Xin phép chú @HUONGHCKT nhé. Tại muốn nghe và hiểu xem cụ thể cái được và mất nếu tách riêng code của Dic ra nó như thế nào? Có gì chú bỏ qua nhé
@VetMini Nhờ chú chỉ dạy thêm ạ.
Đây là code nạp Dic
Mã:
Option Explicit
Public Result(), Dic As Object

Sub Add_Dic()
Dim i&, j&, t&, Lr&
Dim Arr(), Key
Dim Ws As Worksheet
Set Ws = Sheets("Công tháng 02")
Lr = Ws.Cells(Rows.Count, "B").End(xlUp).Row
If Lr < 2 Then Exit Sub
Arr = Ws.Range("A2:AG" & Lr).Value
Set Dic = CreateObject("Scripting.Dictionary")
ReDim Result(1 To UBound(Arr), 1 To 2)
For i = 1 To UBound(Arr)
    Key = Arr(i, 3) & "#" & Arr(i, 2)
    If Not Dic.exists(Key) Then
        t = t + 1: Dic.Add (Key), t
        Result(t, 1) = Key
        Result(t, 2) = Arr(i, 33)
    End If
Next i
End Sub
Và đây là code sử dụng nó ạ
Mã:
Sub KimThoa89()
Dim i&, j&, t&, Lr&
Dim Arr(), Res(), Temp
Dim Ws As Worksheet

Set Ws = Sheets("Check")
Lr = Ws.Cells(Rows.Count, "B").End(xlUp).Row
If Lr < 2 Then Exit Sub
If Dic Is Nothing Then Add_Dic
Arr = Ws.Range("A1:AN" & Lr).Value
ReDim Res(1 To UBound(Arr), 1 To 34)
Ws.Range("H2:H" & Lr).FormulaR1C1 = _
        "=NETWORKDAYS.INTL(RC[-2],RC[-1],""0000001"",{""2022/1/31"";""2022/2/4""})"
For i = 2 To UBound(Arr)
   'Res(i, 1) = Application.WorksheetFunction.NetworkDays(Arr(i, 6), Arr(i, 7), 1, Holiday1, Holiday2)
   Res(i - 1, 2) = Arr(i, 6)
   Res(i - 1, 3) = Arr(i, 7)
   For j = 13 To 40
        Temp = Arr(i, 2) & "#" & Arr(1, j)
            If Dic.exists(Temp) Then Res(i - 1, j - 8) = Result(Dic.Item(Temp), 2)
   Next j
Next i
Ws.Range("I2").Resize(i - 1, 34) = Res
MsgBox "Xong"
End Sub
Cháu xin lắng nghe và cám ơn trước ạ
Như bạn @befaint nhận xét, bạn nên thêm sự kiện khi dữ liệu sheet công tháng 2 thay đổi cần chay lại sub Add_Dic
Với bài nầy tách add dic thành sub riêng không thực sự cần thiết
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn chú @VetMini đã diễn giải để cháu hiểu. Đọc chợt nhận ra rằng. Đúng là trường hợp cần dùng biến toàn cục thì cháu thấy hay có cái Private. Bản thân cháu vẫn mờ mịt về mấy cái vụ toàn cục , với public, private. Cháu sẽ cố gắng tìm hiểu thêm.
Thầy @HieuCD ạ. Nhìn code của anh @befaint. Nó đúng là ở tầm cao hơn rất nhiều so với những gì em đã được đọc và hiểu qua.
Xin cám ơn mọi người đã giành thời gian hướng dẫn. Sẽ đọc và tham khảo thêm để trau dồi kiến thức ạ.
 
Upvote 0
Như bạn @befaint nhận xét, bạn nên thêm sự kiện khi dữ liệu sheet công tháng 2 thay đổi cần chay lại sub Add_Dic
Với bài nầy tách add dic thành sub riêng không thực sự cần thiết
Có chứ anh, trong file gửi kèm đã có code bắt sự kiện ở Sheet Công nợ tháng 2 rồi mà
Mã:
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row >= 2 Then
    If Target.Column = 2 Or Target.Column = 3 Or Target.Column = 40 Then Call Add_Dic
End If
End Sub
Nhân tiện đây xin hỏi các anh đã ghé qua là khi gọi hàm NetworkDays.INTL của Excel thì đề báo lỗi, cụ thể như sau:
Mã:
.....
Res(k,1)= Application.WorksheetFunction.NetworkDays.INTL(Arr(i, 6), Arr(i, 7), 1, Holiday1, Holiday2)
.....
Với Arr(i,6) và Arr(i,7) là hai phần tử có định dạng ngày tháng năm, Hai biến Holiday1, holiday2 được khai báo là Varial, Số 1 trong hàm lúc đầu là "0000001"> Xin các anh lời chỉ dẫn là cần viết thế nào cho đúng để không vấp lỗi.
Trân trọng cảm ơn.
 
Upvote 0
...

Nếu tôi viết code riêng sử dụng đít sần làm bảng tra thì tôi viết thành class module.
Tôi chưa từng viết class module nên qua câu này cố thử viết cái bảng tra để dùng thay cho Vlookup xem sao. Trong quá trình viết, cái gì chưa biết thì hỏi Google.
 
Upvote 0
Có chứ anh, trong file gửi kèm đã có code bắt sự kiện ở Sheet Công nợ tháng 2 rồi mà
Mã:
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Row >= 2 Then
    If Target.Column = 2 Or Target.Column = 3 Or Target.Column = 40 Then Call Add_Dic
End If
End Sub
Nhân tiện đây xin hỏi các anh đã ghé qua là khi gọi hàm NetworkDays.INTL của Excel thì đề báo lỗi, cụ thể như sau:
Mã:
.....
Res(k,1)= Application.WorksheetFunction.NetworkDays.INTL(Arr(i, 6), Arr(i, 7), 1, Holiday1, Holiday2)
.....
Với Arr(i,6) và Arr(i,7) là hai phần tử có định dạng ngày tháng năm, Hai biến Holiday1, holiday2 được khai báo là Varial, Số 1 trong hàm lúc đầu là "0000001"> Xin các anh lời chỉ dẫn là cần viết thế nào cho đúng để không vấp lỗi.
Trân trọng cảm ơn.
Thử bỏ .INTL
Res(k,1)= Application.WorksheetFunction.NetworkDays(Arr(i, 6), Arr(i, 7), 1, Holiday1, Holiday2)
 
Upvote 0
Web KT
Back
Top Bottom