Chuyên đề giải đáp những thắc mắc về code VBA (2 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

maytinhvp01

Thành viên thường trực
Tham gia
27/7/13
Bài viết
390
Được thích
179
Mình muốn nhờ giải thich câu lệnh " If Ran.Cells(d, c) > max Then max = Ran.Cells(d, c) "
trong ví du:
Public Function LonNhat(Ran As Range)
Dim max As Double, v As Integer, d As Integer, c As Integer
max = Ran.Cells(1, 1)
For d = 1 To Ran.Rows.Count
For c = 1 To Ran.Columns.Count
If Ran.Cells(d, c) > max Then max = Ran.Cells(d, c)
Next c
Next d
v = Tim(max, Ran)
LonNhat = max
End Function
-------------------------------------------------------
[INFO1]Thông báo:
Vì topic này:
http://www.giaiphapexcel.com/forum/...ải-thích-các-code-đề-nghị-các-bạn-gửi-vào-đây
đã quá dài nên BQT đóng lại.
Nay tôi mở topic mới với cùng chủ đề: GIẢI THÍCH NHỮNG THẮC MẮC VỀ CODE
Các bạn nếu có nhu cầu giải thích code, vui lòng post tại đây nhé
NDU96081631

[/INFO1]
 
Chỉnh sửa lần cuối bởi điều hành viên:
Ủa ghi lộn chuỗi cái, như vầy mới đúng:
Mã:
 "|12345678901234|12345678901234|12345678901234|"
 "|Senior Manager|Manager|++++++|Ast Manager|++|"
(độn như thế nào để khoảng cách giữa điểm khởi đầu các chức vụ là 15 ký tự

Hay quá được rồi, cái này giống như index trong excel nhỉ. Cảm ơn VetMini
  • PHP:
    dArr(J, 1) = Choose((InStr("|Senior Manager|Manager|++++++|Ast Manager|++|", "|" & Arr(J, 1) & "|") + 14) / 15 + 1, "D", "A", "B", "C")
Mà cái này sao lại 14 và 15+1? Các giá trị ngoài Sennior, Manager, Ast Manager lấy thành D qua từ nào ở code trên vậy nhỉ?
 
Lần chỉnh sửa cuối:
Upvote 0
Mà cái này sao lại 14 và 15+1? Các giá trị ngoài Sennior, Manager, Ast Manager lấy thành D qua từ nào ở code trên vậy nhỉ?

1+14 = 15 --> 15/15 = 1 --> 1+1 = 2 --> choose trị thứ 2 trong "D","A","B","C" thì là "A"
16+14 = 30 --> 30/15 = 2 --> 2+1 = 3 --> choose trị thứ 3 trong "D","A","B","C" thì là "B"
Nếu không tìm được thì hàm Instr trả về 0
0+14 = 14 --> 14/15 = 0,nnnnn --> 0,nnnnn+1 = 1,nnnnn --> bỏ số lẻ còn lại 1 --> choose trị 1 trong "D","A","B","C" thì là "D"
 
Upvote 0
1+14 = 15 --> 15/15 = 1 --> 1+1 = 2 --> choose trị thứ 2 trong "D","A","B","C" thì là "A"
16+14 = 30 --> 30/15 = 2 --> 2+1 = 3 --> choose trị thứ 3 trong "D","A","B","C" thì là "B"
Nếu không tìm được thì hàm Instr trả về 0
0+14 = 14 --> 14/15 = 0,nnnnn --> 0,nnnnn+1 = 1,nnnnn --> bỏ số lẻ còn lại 1 --> choose trị 1 trong "D","A","B","C" thì là "D"

:). Cảm ơn rất nhiều! VetMini
 
Upvote 0
Bạn tham khảo cách tăng lên các dòng lệnh, chớ giảm làm gì?

If Arr(J, 1) = "Senior Manager" Then
dArr(J, 1) = "A"
ElseIf Arr(J, 1) = "Manager" Then
dArr(J, 1) = "B"
ElseIf Arr(J, 1) = "Ast Manager" Then
dArr(J, 1) = "C"
Else
dArr(J, 1) = "D"

Câu lệnh trên có thể giảm bớt if đi được không ạ?
PHP:
Option Explicit
Sub gpeSWITCH()
 Dim J As Long, Arr(), Tmp As Variant
 On Error GoTo LoiCT
 
 Arr() = Range([B2], [B2].End(xlDown))
 ReDim dArr(1 To UBound(Arr()), 1 To 1)
 For J = 1 To UBound(Arr())
    Tmp = Arr(J, 1)
    dArr(J, 1) = Switch(Tmp = "Senior Manager", "A", Tmp = "Manager", "B", Tmp = "Ast Manager", "C")
    If InStr("ABC", dArr(J, 1)) Then
    Else
        MsgBox dArr(J, 1)
    End If
GPE:    Next J
 [D2].Resize(J - 1).Value = dArr()
Err_:                               Exit Sub
LoiCT:
    If Err = 94 Then
        dArr(J, 1) = "D":           Err = 0
        Resume GPE
    Else
        MsgBox Err, , Error:        Resume Err_
    End If
End Sub
 
Upvote 0
Lỗi không gọi được sự kiện SheetSelectionChange

mọi người giúp em lỗi này với nhé. ngồi cả ngày search google rồi, không biết cách khắc phục
nội dung lỗi em có nêu trong file đính kèm
 
Upvote 0
PHP:
Option Explicit
Sub gpeSWITCH()
 Dim J As Long, Arr(), Tmp As Variant
 On Error GoTo LoiCT
 
 Arr() = Range([B2], [B2].End(xlDown))
 ReDim dArr(1 To UBound(Arr()), 1 To 1)
 For J = 1 To UBound(Arr())
    Tmp = Arr(J, 1)
    dArr(J, 1) = Switch(Tmp = "Senior Manager", "A", Tmp = "Manager", "B", Tmp = "Ast Manager", "C")
    If InStr("ABC", dArr(J, 1)) Then
    Else
        MsgBox dArr(J, 1)
    End If
GPE:    Next J
 [D2].Resize(J - 1).Value = dArr()
Err_:                               Exit Sub
LoiCT:
    If Err = 94 Then
        dArr(J, 1) = "D":           Err = 0
        Resume GPE
    Else
        MsgBox Err, , Error:        Resume Err_
    End If
End Sub

Em tưởng rằng thì là if càng nhiều thì code chạy càng chậm :). Nhờ code trên của anh mà em cải tiến code của em như sau:
PHP:
  Arr() = [G9].Resize(Rws).Value

 ReDim dArr(1 To Rws, 1 To 1)

 For J = 1 To UBound(Arr())

 Sht = Arr(J, 1)

 dArr(J, 1) = Switch(Sht = "Senior Manager", "A", Sht = "Manager", "B", Sht = "Ast Manager", "C")

 Next J

 [N9].Resize(Rws).Value = dArr()

Vì giá trị D em không cần. Như thế này không có vấn đề gì anh nhỉ :).
 
Upvote 0
Em tưởng rằng thì là if càng nhiều thì code chạy càng chậm

Khi xét nhiều trường hợp thì select case là hiệu quả nhất (trung bình thì nhanh nhất), kế đó là if-else-if
Các phương pháp khác chỉ để cho đẹp mắt, và chỉ hữu hiệu khi số trường hợp cần xét khong lớn lắm (điển hình <= 6)

Vì giá trị D em không cần. Như thế này không có vấn đề gì anh nhỉ :).

Nếu bảo đảm không xảy ra trường hợp "D" thì dùng hàm Match và Char(64+n), hoặc Mid("ABC",n,1) là gọn nhất
 
Upvote 0
Khi xét nhiều trường hợp thì select case là hiệu quả nhất (trung bình thì nhanh nhất), kế đó là if-else-if
Các phương pháp khác chỉ để cho đẹp mắt, và chỉ hữu hiệu khi số trường hợp cần xét khong lớn lắm (điển hình <= 6)
Nếu bảo đảm không xảy ra trường hợp "D" thì dùng hàm Match và Char(64+n), hoặc Mid("ABC",n,1) là gọn nhất
Như thế nầy được không?
Mã:
Darr(j, 1) = Mid(Arr(j, 1) & "ACCCBBBB", 15, 1)
 
Upvote 0
Như thế nầy được không?
Mã:
Darr(j, 1) = Mid(Arr(j, 1) & "ACCCBBBB", 15, 1)

Theo mình hiểu thì code trên dựa theo việc đếm ký tự của Arr(j,1) như vậy vẫn có những chức vụ khác nhau mà có số ký tự như sau (Ví dụ Ast Manager với Tech Worker). Code rất hay nhưng không dùng được trong trường hợp này rồi đúng không bạn ?
 
Upvote 0
Theo mình hiểu thì code trên dựa theo việc đếm ký tự của Arr(j,1) như vậy vẫn có những chức vụ khác nhau mà có số ký tự như sau (Ví dụ Ast Manager với Tech Worker). Code rất hay nhưng không dùng được trong trường hợp này rồi đúng không bạn ?
các biến tấu đặc biệt cần phải phân tích kỹ lưỡng về qui luật dữ liệu, ở đây là dựa vào sự khác nhau của số ký tự, nếu các giá trị có số ký tự khác nhau thì dùng đươc, nếu có 2 trường hợp số ký tự bằng nhau thì phải dùng cách khác, như tìm 1 ký tự nào đó và dùng hàm Replace chẳng hạn, để chuyển thành số ký tự khác nhau, từ đó mới dùng hàm Mid
 
Lần chỉnh sửa cuối:
Upvote 0
Từ "Senior Manager", "Manager",... chuyển về thành "A", "B", "C",... theo ngôn ngữ CSDL là công việc chuẩn hoá (normalise/ize). Theo ngôn ngữ hành chánh gọi là công việc xếp loại (categorise/ize)
Việc chuẩn hoá luôn luôn rắc rối. Sau khi chuẩn rồi, lúc đó mới dễ làm việc.
 
Upvote 0
Theo mình hiểu thì code trên dựa theo việc đếm ký tự của Arr(j,1) như vậy vẫn có những chức vụ khác nhau mà có số ký tự như sau (Ví dụ Ast Manager với Tech Worker). Code rất hay nhưng không dùng được trong trường hợp này rồi đúng không bạn ?

Lệnh ngắn chưa chắc đã hiệu quả cả cho máy tính dịch, lẫn người viết code đọc lại. Trường hợp này tốt nhất bạn thử dùng Select Case sẽ dễ hiểu và hiệu quả.
 
Upvote 0
Lệnh ngắn chưa chắc đã hiệu quả cả cho máy tính dịch, lẫn người viết code đọc lại. Trường hợp này tốt nhất bạn thử dùng Select Case sẽ dễ hiểu và hiệu quả.
lệnh ngắn hay dài, chạy nhanh hay chậm là tùy theo đặc điểm của dữ liệu và khả năng phân tích dữ liệu, để dể hiểu thì cứ theo các cách thông thường, cứ lối mòm mà đi là an toàn nhất
trường hợp nầy chỉ có 3 khả năng mà dùng select case có vẻ khó hiểu rờm rà hơn Switch nhiều, còn hiệu quả là một khái niệm gắn liền với mục tiêu qui định trước, những mục tiêu khác nhau sẽ đánh giá hiệu quả khác nhau, không thể nói hiệu quả một cách chung chung được
 
Upvote 0
Lệnh ngắn chưa chắc đã hiệu quả cả cho máy tính dịch, lẫn người viết code đọc lại. Trường hợp này tốt nhất bạn thử dùng Select Case sẽ dễ hiểu và hiệu quả.

Vì mình chỉ quan tâm A, B, C nên mình chọn code này của anh ChanhTQ@

PHP:
  Arr() = [G9].Resize(Rws).Value
 ReDim dArr(1 To Rws, 1 To 1)
 For J = 1 To UBound(Arr())
 Sht = Arr(J, 1)
 
 dArr(J, 1) = Switch(Sht = "Senior Manager", "A", Sht = "Manager", "B", Sht = "Ast Manager", "C")
 Next J
 [N9].Resize(Rws).Value = dArr()

Cho mình hỏi thêm trong vba hình như không có biến giờ. Và muốn bao quát hết phải dùng biến Variant phải không mọi người?
 
Upvote 0
Vì mình chỉ quan tâm A, B, C nên mình chọn code này của anh ChanhTQ@

PHP:
  Arr() = [G9].Resize(Rws).Value
 ReDim dArr(1 To Rws, 1 To 1)
 For J = 1 To UBound(Arr())
 Sht = Arr(J, 1)
 
 dArr(J, 1) = Switch(Sht = "Senior Manager", "A", Sht = "Manager", "B", Sht = "Ast Manager", "C")
 Next J
 [N9].Resize(Rws).Value = dArr()

Cho mình hỏi thêm trong vba hình như không có biến giờ. Và muốn bao quát hết phải dùng biến Variant phải không mọi người?
để hiểu hơn về code, bạn nên tìm đọc Help của VBA
trong phần Help của VBA bạn gỏ từ khóa: Dim
chọn lệnh phù hợp và xem hướng dẫn
 
Upvote 0
Switch là hàm chuyển đổi dữ liệu trực tiếp từ một tập hợp xác định sang tập hợp xác định khác (*1)
Nếu trường hợp này chỉ đơn giản dịch "Senior Manager" sang "A", vv... (tức là dịch trực tiếp trị hằng sang trị hằng) thì nó đúng là gọn nhất.

Các cách IF-ELSE-IF, SELECT-CASE, IIF, INSTR,... mục đích chính là để quyết toán những dữ liệu chả khớp vào đâu cả, trường hợp "D"

Trong tất cả các cách, thông thường IF-ELSE-IF là nhanh và an toàn nhất, bởi vì nó là cách tính từ trên xuống, khi đã đạt 1 true rồi thì bỏ qua các chỗ còn lại (*2).

(*1) lưu ý từ "xác định". Nó có nghĩa là ta đã xác định rằng nó "chỉ như thế", không lệch đi đâu cả.

(*2) chỉ đúng với VBA. Ngược lại, ngôn ngữ khác như C chẳng hạn thì Case là lệnh nhanh nhất (C bắt buộc trường hợp Case phải là hằng)

Chú thích về "an toàn":
IF-ELSE-IF được xem như an toàn hơn IIF, SWITCH, và CHOOSE vì lý do sau đây:
ví dụ bẫy lỗi chia cho 0
Code 1:
if (b <> 0) then
x = a/b
else
x = 0
End if
Code 2:
x = Iif( b <> 0, a/b, 0) ' câu lệnh này không bẫy lỗi được, dù b có 0 hay không, VBA vẫn tính biểu thức a/b như thường
Code 3:
x = Switch(b=0, 0, b<>0, a/b) ' cũng không bẫy lỗi được

Nguyên tắc cần ghi nhớ: các hàm tương dương với IF chỉ dùng để viết cho gọn chứ không có nghĩa là hoàn toàn tương đương. Khi tính đoạn code If, VBA chỉ cần xét đến chõ gặp true, và bỏ qua chỗ còn lại. Khi bước vào hàm, VBA phải tính tất cả các biểu thức tham số, không chừa biểu thức nào.
 
Upvote 0
Switch là hàm chuyển đổi dữ liệu trực tiếp từ một tập hợp xác định sang tập hợp xác định khác (*1)
Nếu trường hợp này chỉ đơn giản dịch "Senior Manager" sang "A", vv... (tức là dịch trực tiếp trị hằng sang trị hằng) thì nó đúng là gọn nhất.

Các cách IF-ELSE-IF, SELECT-CASE, IIF, INSTR,... mục đích chính là để quyết toán những dữ liệu chả khớp vào đâu cả, trường hợp "D"

Trong tất cả các cách, thông thường IF-ELSE-IF là nhanh và an toàn nhất, bởi vì nó là cách tính từ trên xuống, khi đã đạt 1 true rồi thì bỏ qua các chỗ còn lại (*2).

(*1) lưu ý từ "xác định". Nó có nghĩa là ta đã xác định rằng nó "chỉ như thế", không lệch đi đâu cả.

(*2) chỉ đúng với VBA. Ngược lại, ngôn ngữ khác như C chẳng hạn thì Case là lệnh nhanh nhất (C bắt buộc trường hợp Case phải là hằng)

Chú thích về "an toàn":
IF-ELSE-IF được xem như an toàn hơn IIF, SWITCH, và CHOOSE vì lý do sau đây:
ví dụ bẫy lỗi chia cho 0
Code 1:
if (b <> 0) then
x = a/b
else
x = 0
End if
Code 2:
x = Iif( b <> 0, a/b, 0) ' câu lệnh này không bẫy lỗi được, dù b có 0 hay không, VBA vẫn tính biểu thức a/b như thường
Code 3:
x = Switch(b=0, 0, b<>0, a/b) ' cũng không bẫy lỗi được

Nguyên tắc cần ghi nhớ: các hàm tương dương với IF chỉ dùng để viết cho gọn chứ không có nghĩa là hoàn toàn tương đương. Khi tính đoạn code If, VBA chỉ cần xét đến chõ gặp true, và bỏ qua chỗ còn lại. Khi bước vào hàm, VBA phải tính tất cả các biểu thức tham số, không chừa biểu thức nào.
Cám ơn bạn, các kiến thức căn bản nầy rất bổ ích cho mình và rất nhiều người, trước đây mình chỉ mang máng và làm theo cảm giác, bây giờ mới hiểu tường tận vấn đề
chúc bạn năm mới dồi dào sức khỏe, vạn sự như ý /-*+//-*+//-*+/
 
Upvote 0
Nhờ các bạn xử lý dùm trong trường hợp này Mình sử dụng Hàm Find nó sai cái gì mà lỗi code ....yêu cầu mong muốn Mình ghi kèm trong File
Mã:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
    If Not Intersect(Target, [D6:D82]) Is Nothing Then
        'If Target.Offset(, -2) > Sheet2.[B6:B20].Find(Target).Offset(, 2) Then
        If Target.Value > Sheet2.[B:B].Find(Target).Offset(, 2) Then
            MsgBox "ok"
        End If
    End If
Application.EnableEvents = True
End Sub

Xin cảm ơn
 

File đính kèm

Upvote 0
Nhờ các bạn xử lý dùm trong trường hợp này Mình sử dụng Hàm Find nó sai cái gì mà lỗi code ....yêu cầu mong muốn Mình ghi kèm trong File
Mã:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
    If Not Intersect(Target, [D6:D82]) Is Nothing Then
        'If Target.Offset(, -2) > Sheet2.[B6:B20].Find(Target).Offset(, 2) Then
        If Target.Value > Sheet2.[B:B].Find(Target).Offset(, 2) Then
            MsgBox "ok"
        End If
    End If
Application.EnableEvents = True
End Sub

Xin cảm ơn
vụ nầy hơi nghi ngờ, làm đại sai đúng hên xui
Mã:
If Target.Value > Sheet2.[B:B].Find(Target.Offset(, -2)).Offset(, 2) Then
 
Upvote 0
Web KT

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

Back
Top Bottom