Thảo luận về IF, AND, OR... trong lập trình VBA (1 người xem)

  • Thread starter Thread starter VetMini
  • Ngày gửi Ngày gửi
Liên hệ QC

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

VetMini

Đang đi tìm hòn đá
Tham gia
21/12/12
Bài viết
17,868
Được thích
24,777
Nghề nghiệp
Thầy bói bài ta
Bạn mô tả kiểu võ lâm thì mình làm theo kiểu thiếu lâm tự nhé, còn thiếu xíu nữa là hoàn chỉnh bạn tự bổ sung nhé. Khi nào siêng thì rút gọn code lại tí

Đúng ra Sub này nên tách ra làm 2 sub. Nếu H7 <> "" thì chạy 1 Sub và ngược lại
PHP:
Sub loc()
Dim Data(), Res(), i, j, k
[A13:H5000].ClearContents
Data = Sheet1.Range(Sheet1.[AB9], Sheet1.[AB65536].End(3)).Resize(, 10).Value
ReDim Res(1 To UBound(Data), 1 To 8)
For i = 1 To UBound(Data)
   If Data(i, 1) >= [D5].Value Then
      If Data(i, 1) <= [D6].Value Then
         If [H7].Value = "" Then
            If Data(i, 9) = [H6].Value Or Data(i, 8) = [H6].Value Then
               k = k + 1
               Res(k, 1) = Data(i, 1)
               Res(k, 2) = Data(i, 2)
               Res(k, 3) = Data(i, 3)
               Res(k, 4) = Data(i, 5)
               Res(k, 5) = Data(i, 7)
               If Data(i, 8) = [H6].Value Then Res(k, 6) = Data(i, 9)
               If Data(i, 9) = [H6].Value Then Res(k, 6) = Data(i, 8)
               If Data(i, 8) = [H6].Value Then Res(k, 7) = Data(i, 10)
               If Data(i, 9) = [H6].Value Then Res(k, 8) = Data(i, 10)
            End If
         Else
            If Data(i, 6) = [H7].Value Then
                If Data(i, 9) = [H6].Value Or Data(i, 8) = [H6].Value Then
                  k = k + 1
                  Res(k, 1) = Data(i, 1)
                  Res(k, 2) = Data(i, 2)
                  Res(k, 3) = Data(i, 3)
                  Res(k, 4) = Data(i, 5)
                  Res(k, 5) = Data(i, 7)
                  If Data(i, 8) = [H6].Value Then Res(k, 6) = Data(i, 9)
                  If Data(i, 9) = [H6].Value Then Res(k, 6) = Data(i, 8)
                  If Data(i, 8) = [H6].Value Then Res(k, 7) = Data(i, 10)
                  If Data(i, 9) = [H6].Value Then Res(k, 8) = Data(i, 10)
               End If
            End If
         End If
      End If
   End If
Next
k = k + 1
Res(k, 7) = "=sum(R13C:R[-1]C)"
Res(k, 8) = "=sum(R13C:R[-1]C)"
[A13].Resize(k, 8) = Res
End Sub

Không cần phải vậy. Các IF's trong bài này lồng trơn vào nhau - tức là không có lệnh khác. Như vậy ta có thể dùng AND. Phần code trong ELSE cũng in hệt như IF, nên có thể dùng OR

PHP:
   If Data(i, 1) >= [D5].Value AND Data(i, 1) <= [D6].Value _ ' trong giới hạn ngày '
         AND ([H7].Value = "" OR Data(i, 6) = [H7].Value) _ ' đúng mã KH '
            AND (Data(i, 9) = [H6].Value Or Data(i, 8) = [H6].Value) Then ' dúng mã tài khoản đối chiếu '
               k = k + 1
               Res(k, 1) = Data(i, 1)
               Res(k, 2) = Data(i, 2)
               Res(k, 3) = Data(i, 3)
               Res(k, 4) = Data(i, 5)
               Res(k, 5) = Data(i, 7)
               ' If Data(i, 8) = [H6].Value Then Res(k, 6) = Data(i, 9) '
               ' If Data(i, 9) = [H6].Value Then Res(k, 6) = Data(i, 8) '
               ' If Data(i, 8) = [H6].Value Then Res(k, 7) = Data(i, 10) '
               ' If Data(i, 9) = [H6].Value Then Res(k, 8) = Data(i, 10) '
               ' điều kiện đã thử rồi, [H6].Value bắt buộc phải = Data(i, 8 hoặc 9) '
               Res(k, 6) = Data(i, Iif(Data(i, 8) = [H6].Value, 9, 8))
               Res(k, Iif(Data(i, 8) = [H6].Value, 7, 8)) = Data(i, 10)
   End If
 
Lần chỉnh sửa cuối:
Không cần phải vậy. Các IF's trong bài này lồng trơn vào nhau - tức là không có lệnh khác. Như vậy ta có thể dùng AND. Phần code trong ELSE cũng in hệt như IF, nên có thể dùng OR

PHP:
   If Data(i, 1) >= [D5].Value AND Data(i, 1) <= [D6].Value _ ' trong giới hạn ngày '
         AND ([H7].Value = "" OR Data(i, 6) = [H7].Value) _ ' đúng mã KH '
            AND (Data(i, 9) = [H6].Value Or Data(i, 8) = [H6].Value) Then ' dúng mã tài khoản đối chiếu '
               k = k + 1
               Res(k, 1) = Data(i, 1)
               Res(k, 2) = Data(i, 2)
               Res(k, 3) = Data(i, 3)
               Res(k, 4) = Data(i, 5)
               Res(k, 5) = Data(i, 7)
               ' If Data(i, 8) = [H6].Value Then Res(k, 6) = Data(i, 9) '
               ' If Data(i, 9) = [H6].Value Then Res(k, 6) = Data(i, 8) '
               ' If Data(i, 8) = [H6].Value Then Res(k, 7) = Data(i, 10) '
               ' If Data(i, 9) = [H6].Value Then Res(k, 8) = Data(i, 10) '
               ' điều kiện đã thử rồi, [H6].Value bắt buộc phải = Data(i, 8 hoặc 9) '
               Res(k, 6) = Data(i, Iif(Data(i, 8) = [H6].Value, 9, 8))
               Res(k, Iif(Data(i, 8) = [H6].Value, 7, 8)) = Data(i, 10)
   End If
Hic mình nhắm mắt viết chứ có hiểu mấy đâu. Trúng ý của tác giả là hên lắm rồi. Còn vụ rút gọn phải để cho khổ chủ có việc làm chứ. Mình chỉ khoái mần nửa chừng vậy mà. Mọi người biết rõ cái tật lớn của mình là vậy. Viết code phải 3 lần mới chạy.
 
Upvote 0
Không cần phải vậy. Các IF's trong bài này lồng trơn vào nhau - tức là không có lệnh khác. Như vậy ta có thể dùng AND. Phần code trong ELSE cũng in hệt như IF, nên có thể dùng OR

PHP:
   If Data(i, 1) >= [D5].Value AND Data(i, 1) <= [D6].Value _ ' trong giới hạn ngày '
         AND ([H7].Value = "" OR Data(i, 6) = [H7].Value) _ ' đúng mã KH '
            AND (Data(i, 9) = [H6].Value Or Data(i, 8) = [H6].Value) Then ' dúng mã tài khoản đối chiếu '
               k = k + 1
               Res(k, 1) = Data(i, 1)
               Res(k, 2) = Data(i, 2)
               Res(k, 3) = Data(i, 3)
               Res(k, 4) = Data(i, 5)
               Res(k, 5) = Data(i, 7)
               ' If Data(i, 8) = [H6].Value Then Res(k, 6) = Data(i, 9) '
               ' If Data(i, 9) = [H6].Value Then Res(k, 6) = Data(i, 8) '
               ' If Data(i, 8) = [H6].Value Then Res(k, 7) = Data(i, 10) '
               ' If Data(i, 9) = [H6].Value Then Res(k, 8) = Data(i, 10) '
               ' điều kiện đã thử rồi, [H6].Value bắt buộc phải = Data(i, 8 hoặc 9) '
               Res(k, 6) = Data(i, Iif(Data(i, 8) = [H6].Value, 9, 8))
               Res(k, Iif(Data(i, 8) = [H6].Value, 7, 8)) = Data(i, 10)
   End If

Nếu tôi không lầm thì code của Hải là chuẩn hơn code của bạn.
Ta lấy ví dụ trong lập trình Delphi (thực ra tôi làm nhiều trong Delphi nên hiểu Delphi hơn là Visual Basic nên xét Delphi thôi)
Khi Delphi gặp cấu trúc "IF A and B and C ... and Z then"
thì: Delphi xét từ đk đầu, ở đây là A. Nếu A = TRUE thì xét tiếp đk tiếp theo, cứ thế cho tới đk cuối cùng. Nếu đk hiện hành = FALSE thì Delphi KHÔNG XÉT các đk tiếp theo nữa mà kết luận là "A and B and C ... and Z = FALSE". Rõ ràng Delphi làm như thế là đúng và hợp lý vì 1 đk = FALSE trong cấu trúc trên nghĩa là đk tổng quát = FALSE, chả lý gì mà xét các đk tiếp theo làm gì cho tốn "điện nước".
Nhưng VBA lại không thao tác hợp lý như thế. Dù cho có 1 đk nào = FALSE thì "nó" vẫn tính tất cả các đk rồi trên cơ sở đó tính đk tổng quát.
Tóm lại trong Delphi nếu bạn có n đk thì xấu nhất là Delphi tính n đk (khi n - 1 đk đầu = TRUE) nhưng có thể chỉ tính 1 đk (khi đk đầu tiên = FALSE). Còn trong VBA thì LUÔN tính n đk.

Các bạn hãy chạy Sub he sau:

Mã:
Sub [COLOR=#ff0000]he[/COLOR]()
Dim a As Long
    a = 10
    If a < 9 And bla(a) Then
        MsgBox "good"
    Else
        MsgBox "bad"
    End If
End Sub

Function [COLOR=#ff0000]bla[/COLOR](ByVal a As Long) As Boolean
    If a < 5 Then
        bla = False
    Else
        bla = True
    End If
    MsgBox "bla"
End Function

Rõ ràng đk (a < 9) = FALSE nên cho dù bla trả về TRUE hay FALSE thì đk "a < 9 And bla(a)" = FALSE. Vậy chả lý gì phả tính bla cho tốn "điện nước". Nhưng chạy sub he ta thấy hàm bla vẫn được thực hiện.
-------------
Từ đây ta thấy nếu trong code của Hải đk của IF đầu tiên = FALSE thì những đk của các IF sau sẽ không phải tính. Còn trong code của bạn thì chúng được tính hết. Nếu các đk này đơn giản thì tốn thêm chút điện nước cũng chả sao nhưng ta thử tưởng tượng là trong những trường hợp khác khi các đk tiếp theo chứa giá trị do các hàm nào đó trả về mà code của các hàm ấy tính toán nhiều thì "điện nước" sẽ lớn, phí phạm sẽ lớn.
 
Upvote 0
Còn vụ rút gọn phải để cho khổ chủ có việc làm chứ. Mình chỉ khoái mần nửa chừng vậy mà.

Ấy, khoan đã. Ta thử xét vụ rút gọn này xem có hợp lý không đã. Theo tôi là không hợp lý. Các bạn khác cho ý kiến nhé.
Rút gọn không sai nhưng nếu ta biết được VBA thao tác như thế nào thì ta sẽ biết viết code tối ưu hơn
 
Upvote 0
Ấy, khoan đã. Ta thử xét vụ rút gọn này xem có hợp lý không đã. Theo tôi là không hợp lý. Các bạn khác cho ý kiến nhé.
Rút gọn không sai nhưng nếu ta biết được VBA thao tác như thế nào thì ta sẽ biết viết code tối ưu hơn

Tôi cũng nghĩ như siwtom. Khi 1 điều kiện False sẽ không cần xét những điều kiện còn lại mà chạy thẳng đến Else. Tốc độ cũng tăng đáng kể.

Ngoài ra, tôi đã từng bị lỗi với nhiều điều kiện kết hợp bằng and, or. Viết thêm mấy dòng If không mất công bao nhiêu mà ít bị lỗi hơn, và lỗi dễ tìm để sửa hơn.

Lỗi thí dụ như: Đặt điều kiện a>0 mà a tại 1 dòng dữ liệu nào đó tình cờ lại là text. Nếu 4 điều kiện 4 If, thì khi debug, biết ngay đang lỗi ở dòng chứa điều kiện nào. Nếu 4 điều kiện 1 If với 3 And, khi debug không biết đang lỗi điều kiện nào, vì dòng đó đang chứa cả 4 điều kiện.

2. Ngoài ra tôi cũng ít dùng hàm IIf. Hàm IIf(condition, value if true, value if false), thì cả 3 tham số đều không được lỗi. Thí dụ:

n = a - b
MyResult = IIf(n < 0, n, n ^ (1/2))

nếu n > 0 thì không nói làm gì, nó rút căn bậc 2 của n và ra kết quả.

Chạy đến 1 lúc nào đó a - b < 0, điều kiện thỏa, nhưng vẫn báo lỗi rút căn bậc 2 của số âm, dù ta không xài kết quả đó.
 
Upvote 0
Tôi cũng nghĩ như siwtom. Khi 1 điều kiện False sẽ không cần xét những điều kiện còn lại mà chạy thẳng đến Else. Tốc độ cũng tăng đáng kể.

Ngoài ra, tôi đã từng bị lỗi với nhiều điều kiện kết hợp bằng and, or. Viết thêm mấy dòng If không mất công bao nhiêu mà ít bị lỗi hơn, và lỗi dễ tìm để sửa hơn.

Lỗi thí dụ như: Đặt điều kiện a>0 mà a tại 1 dòng dữ liệu nào đó tình cờ lại là text. Nếu 4 điều kiện 4 If, thì khi debug, biết ngay đang lỗi ở dòng chứa điều kiện nào. Nếu 4 điều kiện 1 If với 3 And, khi debug không biết đang lỗi điều kiện nào, vì dòng đó đang chứa cả 4 điều kiện.

2. Ngoài ra tôi cũng ít dùng hàm IIf. Hàm IIf(condition, value if true, value if false), thì cả 3 tham số đều không được lỗi. Thí dụ:

n = a - b
MyResult = IIf(n < 0, n, n ^ (1/2))

nếu n > 0 thì không nói làm gì, nó rút căn bậc 2 của n và ra kết quả.

Chạy đến 1 lúc nào đó a - b < 0, điều kiện thỏa, nhưng vẫn báo lỗi rút căn bậc 2 của số âm, dù ta không xài kết quả đó.

Thực ra tôi viết: "Rút gọn không sai" là chưa rõ ràng. Vì trong trường hợp này không sai nhưng trong trường hợp khác có thể sai - đi đêm lắm sẽ có ngày gặp ma mà.

Vì có những tình huống khi mà A = TRUE thì KHÔNG BAO GIỜ CÓ LỖI ở B nhưng khi A = FALSE thì B có thể có lỗi. Lúc đó dùng 2 IF thì không có lỗi nhưng thay bằng AND thì có lỗi.
Ví dụ như code, đơn giản thôi vì chỉ để miêu tả vấn đề:

Mã:
Dim sp As Shape

Sub he()
    If Not sp Is Nothing Then
        If sp.Name = "hic hic" Then
            MsgBox "good"
        End If
    End If
End Sub

Sub bla()
    If Not sp Is Nothing And sp.Name = "hic hic" Then
            MsgBox "good"
    End If
End Sub

Giả sử sp = NOTHING. Lúc này chạy code he không có lỗi nhưng code bla có lỗi.
 
Upvote 0
Luật "thấy code thì tính" của VBA (hình như áp dụng cho hầu hết các ngôn ngữ dòng họ Basic) không được hiệu quả như luật "cần mới tính" của dòng họ C. Tuy nhiên tôi chỉ nghĩ tới tốc độ khi gặp những ứng dụng dùng thường xuyên, và ứng dụng có độ quan trọng cần sử lý kịp thời.

Ứng dụng này là mỗi tháng chạy vài lần, một lần chạy tối đa vài chục sheets (nhiều hơn nữa mà dùng Excel là tự đào hố chôn mình). Điểm quan trọng hơn là viết làm sao cho dễ sửa. Một đoạn code lặp lại hai lần chắc chắn là không thuộc loại dễ sửa rồi.

Việc thêm mấy dòng IF's cho dễ sửa thuỳ theo thói quen. Thí dụ như tôi thì không ngại số IF's nhưng lại ngại số END IF's

Hàm IIF chẳng có gì phải ngại nếu dùng với literals. Bính thường thì người ta chỉ tránh dùng nó khi gọi functions:

IIF( điều kiện, gọi hàm 1, gọi hàm 2 )

Nếu muốn đo từng lệnh máy (machine instruction) thì có thể phê bình IIF là hàm, phải qua thủ tục nối, gọi hàm rất rườm rà; trong khi IF là lệnh rẽ nhánh, nhanh hơn nhiều.
 
Lần chỉnh sửa cuối:
Upvote 0
Luật "thấy code thì tính" của VBA (hình như áp dụng cho hầu hết các ngôn ngữ dòng họ Basic) không được hiệu quả như luật "cần mới tính" của dòng họ C. Tuy nhiên tôi chỉ nghĩ tới tốc độ khi gặp những ứng dụng dùng thường xuyên, và ứng dụng có độ quan trọng cần sử lý kịp thời.

Ứng dụng này là mỗi tháng chạy vài lần, một lần chạy tối đa vài chục sheets (nhiều hơn nữa mà dùng Excel là tự đào hố chôn mình). Điểm quan trọng hơn là viết làm sao cho dễ sửa. Một đoạn code lặp lại hai lần chắc chắn là không thuộc loại dễ sửa rồi.

Việc thêm mấy dòng IF's cho dễ sửa thuỳ theo thói quen. Thí dụ như tôi thì không ngại số IF's nhưng lại ngại số END IF's

Hàm IIF chẳng có gì phải ngại nếu dùng với literals. Bính thường thì người ta chỉ tránh dùng nó khi gọi functions:

IIF( điều kiện, gọi hàm 1, gọi hàm 2 )

Nếu muốn đo từng lệnh máy (machine instruction) thì có thể phê bình IIF là hàm, phải qua thủ tục nối, gọi hàm rất rườm rà; trong khi IF là lệnh rẽ nhánh, nhanh hơn nhiều.

1. Ta bàn ở đây là để ý thức cho mọi người cái "bẫy" mà rất có thể ta sẽ sa vào. Nhiều người không rành lắm chỉ "học" theo các bậc sư phụ thì họ không biết và biết đâu sau này cứ có 1 loạt IF họ lại gộp thành AND thì sao?
2. Nếu một người không biết gì mà viết như bạn thì tôi có khi cũng chả góp ý làm gì. Nhưng tôi biết bạn biết về lập trình, vậy ta bàn với nhau về mặt lý thuyết, về nguyên tắc lập trình.
3. Nhiều người "bình thường" sai nhưng tôi không có hứng để bàn luận. Nhưng nếu đó là người có uy tín thì thường tôi thấy "ngứa tay". Nhiều người hiểu lầm là tôi cố ý hạ uy tín của cao thủ kia là thế.
Nhưng không phải như vậy. Nếu A là "gà" mà A viết sai thì tai hại không đáng kể, cùng lắm A chỉ hại mình thôi. Nhưng nếu A là "uy tín", lời nói của A có hàng triệu người nghe, mỗi lời phán mọi người chấp nhận như tiên đề thì sao? Nếu không chỉ ra cái sai của A thì có nghĩa là chấp nhận triệu người ấy cũng làm sai như A. Nếu A sai thì hậu quả khôn lường. Vì thế nên chỉ ra cái sai của A, ý thức cho mọi người những cái bẫy đang đợi.
 
Upvote 0
Tôi thì chưa thấy được cái sai của cao thủ, nhưng tôi viết về hàm IIf vì bản thân tôi đã gặp phải, và tôi muốn cảnh báo những người đang tập tành học để đừng lúng túng giống tôi khi tôi gặp lỗi hàm IIf lần đầu tiên: Lập luận đúng, thuật toán đúng, hàm dùng đúng, thủ thuật cũng đúng, ... Mà kết quả cứ báo lỗi. Chỉ vì không biết các nguyên lý hoạt động của cái mình đang dùng.
 
Lần chỉnh sửa cuối:
Upvote 0
Đáng lẽ thì bàn luận đến đây thì đủ rồi. Nhưng đã nói chuyện "dẫn dắt cừu non" thì bắt buộc tôi phải biện luận.

Theo quan niệm chính tôi thì con nguời có khả năng hướng thiện. Người có ý chí lập trình tự động tìm ra con đường tốt cho mình.

"Lập trình viên chân chính không dùng lệnh GoTo, lập trình viên lão thành không cần lý đến luật này" (real programmers don't use goto, experienced programmers ignore this rule)

Cũng giống như lệnh goto, những điều nguy hiểm của những lênh/hàm nguy hiểm hầu như không thể xảy ra cho một lập trình viên có căn bản. Một khi code có khả năng nguy hiểm thì người ta tự động biết cách tránh.

Nếu muốn giải thích cái khác nhau giữa IF dkA THEN IF dkB và IF (dkA AND dkB) thì giải thích luôn cho cặn kẽ:

Toán tử AND mặc định rằng 2 điều kiện là một nhóm điều kiện trong khi THEN IF mặc định rằng đó là hai điều kiện riêng biệt, cái sau lồng vào cái trước.

Một nhóm điều kiện điều khiển vận hành của cả block cho tới từ khoá kết block (END IF). Hai điều kiện riêng biệt thì có thể xảy ra trường hợp block bên trong đạt đến kết nhưng block bên ngoài còn chứa một số code. Điều này không hẳn đã là "code phản ánh lô gic" (vì vậy trước đây tôi mới đề cập đến vấn đề kiểm tra các từ khoá END IF)

Riêng trong trường hợp của Basic muốn bàn về error thì bàn thêm như thế này:
nếu code đang nằm trong phạm vi hoạt động (scope) của định tính "On Error Resume Next" thì IF (một nhóm điều kiện) khác với IF (kiều kiện a) THEN IF (điều kiện b) ở chỗ nếu xảy ra error trong lúc xét đièu kiên a thì ở trường hợp nhóm execution engine coi như cả nhóm đạt điều kiện trong khi ở trường hợp tuần tự execution engine còn tiếp tục xét điều kiện b. Lối vận hành nào nguy hiểm hơn tuỳ theo quan niệm cá nhân.

MyResult = IIf(n < 0, n, n ^ (1/2))
Như đã nói trước đây, IIF cũng như GoTo, người dùng tự động biết cách tránh lỗi. Trên nguyên tắc thì người ta chỉ dùng cho literals (giống như hàm Choose)

Mã:
Sub [COLOR=#ff0000]he[/COLOR]() Dim a As Long
    a = 10 
    If a < 9 And bla(a) Then
         MsgBox "good" 
    Else
         MsgBox "bad"
     End If 
End Sub

  Function [COLOR=#ff0000]bla[/COLOR](ByVal a As Long) As Boolean
     If a < 5 Then
         bla = False
     Else
         bla = True
     End If     MsgBox "bla"
 End Function

Sub he() Dim a As Long a = 10 If a < 9 And bla(a) Then MsgBox "good" Else MsgBox "bad" End If End Sub Function bla(ByVal a As Long) As Boolean If a < 5 Then bla = False Else bla = True End If MsgBox "bla" End Function
Rõ ràng đk (a < 9) = FALSE nên cho dù bla trả về TRUE hay FALSE thì đk "a < 9 And bla(a)" = FALSE. Vậy chả lý gì phả tính bla cho tốn "điện nước". Nhưng chạy sub he ta thấy hàm bla vẫn được thực hiện.

Khi đem function làm tham số cho hàm (tạm ví IF ở đây là một hàm, và điều kiện tính là tham số), người ta luôn luôn cân nhắc lợi hại. Nhất là trường hợp dùng biến toàn cục. Đối với Basic, người ta làm tuỳ theo trường hợp có muốn hàm LUÔN LUÔN được gọi hay không. Đây là chưa kể tới truờng hợp nếu vận hành của hàm tham số làm biến đổi giá trị của một tham số khác.

Khi nói tới chuyện đem gộp các điều kiện lại thành một nhóm, tôi chỉ nói cho trường hợp thông thường thôi. Các bạn dẫn ra những trường hợp ngặt nghèo mà đáng lẽ một người viết code đàng hoàng không bao giờ vuớng phải.

Khi nói "dùng Goto cũng chẳng sao" không có nghĩa là bất cứ lệnh rẽ nhánh nào cũng dùng được.
 
Upvote 0
Xuất phát từ topic này:
http://www.giaiphapexcel.com/forum/...ột-thành-1-cột-tách-1-cột-thành-2-cột-theo-ĐK
Các cao thủ đã có cuộc tranh luận sôi nỗi qua việc dùng nhiều IF hoặc gộp lại chúng bằng AND và OR
Xét thấy việc tranh luận này rất bổ ích, giúp cho các thành viên mới học lập trình (như tôi) có cái nhìn sâu sắc hơn. Tuy nhiên để chung với topic của Hong.Van thì lại không hợp với chủ đề, tôi mạn phép dời toàn bộ các bài viết thảo luận sang đây!
Xin mời các cao thủ TIẾP TỤC
 
Upvote 0
Tôi thì chưa thấy được cái sai của cao thủ, nhưng tôi viết về hàm IIf vì bản thân tôi đã gặp phải, và tôi muốn cảnh báo những người đang tập tành học để đừng lúng túng giống tôi khi tôi gặp lỗi hàm IIf lần đầu tiên: Lập luận đúng, thuật toán đúng, hàm dùng đúng, thủ thuật cũng đúng, ... Mà kết quả cứ báo lỗi. Chỉ vì không biết các nguyên lý hoạt động của cái mình đang dùng.

Em không biết gì về nguyên lý hoạt động của các hàm, em thường lấy dữ liệu lớn để test về thời gian, cái nào chạy đúng và nhanh em sẽ sử dụng.

Qua việc Sư phụ nhắc đến hàm IIF, trước đây em cũng đã kiểm tra, thấy nó xét tất cả các đối số TRUE, FALSE trong đó, vì thế nếu các điều kiện loại trừ trong đối số bị lỗi sẽ báo lỗi, mặt khác, nếu dùng hàm này trong một số điều kiện cụ thể với dữ liệu ít (chừng 1000 dòng) thì được, nhưng khi vài chục ngàn dòng, em đã test thì dùng IF ... THEN chạy nhanh hơn vì nó có tính rẽ nhánh, nếu nó tìm đúng, ngay lập tức thủ tục trong nó được tính toán, còn không nó chạy đến END IF tức thì.

Nhưng IF vẫn chưa nhanh bằng SELECT CASE.

Nếu như ta có For i = 1 to 10, cái ta cần giá trị từ 1 đến 8 và giá trị khác từ 9 đến 10, nếu ta dùng IF có lẽ ta viết:

If i = 1 Or i = 2 Or ... Or i = 8 Then

ElseIf i = 9 Or i = 10 Then

End If

Nếu viết như vậy thì tính hơi bị mệt!

Tuy nhiên với Select Case thì quá đơn giản, không OR hay AND gì cả:

Select Case i
Case 1 To 8
Case 9, 10
End Select


Với nhiều điều kiện, để tăng tốc cũng như tường minh, ta nên chọn SELECT CASE.
 
Upvote 0
Đáng lẽ thì bàn luận đến đây thì đủ rồi. Nhưng đã nói chuyện "dẫn dắt cừu non" thì bắt buộc tôi phải biện luận.

Theo quan niệm chính tôi thì con nguời có khả năng hướng thiện. Người có ý chí lập trình tự động tìm ra con đường tốt cho mình.

"Lập trình viên chân chính không dùng lệnh GoTo, lập trình viên lão thành không cần lý đến luật này" (real programmers don't use goto, experienced programmers ignore this rule)

Cũng giống như lệnh goto, những điều nguy hiểm của những lênh/hàm nguy hiểm hầu như không thể xảy ra cho một lập trình viên có căn bản. Một khi code có khả năng nguy hiểm thì người ta tự động biết cách tránh.

Nếu muốn giải thích cái khác nhau giữa IF dkA THEN IF dkB và IF (dkA AND dkB) thì giải thích luôn cho cặn kẽ:

Toán tử AND mặc định rằng 2 điều kiện là một nhóm điều kiện trong khi THEN IF mặc định rằng đó là hai điều kiện riêng biệt, cái sau lồng vào cái trước.

Một nhóm điều kiện điều khiển vận hành của cả block cho tới từ khoá kết block (END IF). Hai điều kiện riêng biệt thì có thể xảy ra trường hợp block bên trong đạt đến kết nhưng block bên ngoài còn chứa một số code. Điều này không hẳn đã là "code phản ánh lô gic" (vì vậy trước đây tôi mới đề cập đến vấn đề kiểm tra các từ khoá END IF)

Riêng trong trường hợp của Basic muốn bàn về error thì bàn thêm như thế này:
nếu code đang nằm trong phạm vi hoạt động (scope) của định tính "On Error Resume Next" thì IF (một nhóm điều kiện) khác với IF (kiều kiện a) THEN IF (điều kiện b) ở chỗ nếu xảy ra error trong lúc xét đièu kiên a thì ở trường hợp nhóm execution engine coi như cả nhóm đạt điều kiện trong khi ở trường hợp tuần tự execution engine còn tiếp tục xét điều kiện b. Lối vận hành nào nguy hiểm hơn tuỳ theo quan niệm cá nhân.


Như đã nói trước đây, IIF cũng như GoTo, người dùng tự động biết cách tránh lỗi. Trên nguyên tắc thì người ta chỉ dùng cho literals (giống như hàm Choose)



Khi đem function làm tham số cho hàm (tạm ví IF ở đây là một hàm, và điều kiện tính là tham số), người ta luôn luôn cân nhắc lợi hại. Nhất là trường hợp dùng biến toàn cục. Đối với Basic, người ta làm tuỳ theo trường hợp có muốn hàm LUÔN LUÔN được gọi hay không. Đây là chưa kể tới truờng hợp nếu vận hành của hàm tham số làm biến đổi giá trị của một tham số khác.

Khi nói tới chuyện đem gộp các điều kiện lại thành một nhóm, tôi chỉ nói cho trường hợp thông thường thôi. Các bạn dẫn ra những trường hợp ngặt nghèo mà đáng lẽ một người viết code đàng hoàng không bao giờ vuớng phải.

Khi nói "dùng Goto cũng chẳng sao" không có nghĩa là bất cứ lệnh rẽ nhánh nào cũng dùng được.

Tôi ý thức được và chắc bạn cũng ý thức được là tôi viết không phải với ý "mở mang" cho bạn, và bạn viết không phải để mở mang cho tôi.
Có bao thành viên khác, và cả bao không thành viên khác, âm thầm đọc bài của bạn và của tôi. Nếu họ đều là những người lập trình có kinh nghiệm thì chả có gì để nói. Vì lúc đó như bạn nói:
"Lập trình viên chân chính không dùng lệnh GoTo, lập trình viên lão thành không cần lý đến luật này" (real programmers don't use goto, experienced programmers ignore this rule)

Cũng giống như lệnh goto, những điều nguy hiểm của những lênh/hàm nguy hiểm hầu như không thể xảy ra cho một lập trình viên có căn bản. Một khi code có khả năng nguy hiểm thì người ta tự động biết cách tránh.

Đối tượng mà tôi muốn viết cho họ là những người chưa có kinh nghiệm. Nếu họ đọc:

Không cần phải vậy. Các IF's trong bài này lồng trơn vào nhau - tức là không có lệnh khác. Như vậy ta có thể dùng AND. Phần code trong ELSE cũng in hệt như IF, nên có thể dùng OR

thì họ, những người chưa có kinh nghiệm, sẽ nghĩ: ừ nhỉ, có lý. Tôi chỉ muốn chỉ ra cho họ những cái "bẫy" đang chờ. Không chỉ là code không tối ưu mà có thể trong một trường hợp nào đấy code bị sai.
Tôi trả lời bài viết của bạn nhưng tôi viết cho những người đang và sẽ đọc bài của bạn. Bạn có hiểu không? Đâu chỉ có tôi và bạn đọc bài của nhau? Phải giải thích cho họ chứ nếu họ không ý thức được những cái mà tôi, bạn hay ptm0412 biết mà cứ "nhắm mắt" làm theo thì nguy to.

À mà:

Khi nói tới chuyện đem gộp các điều kiện lại thành một nhóm, tôi chỉ nói cho trường hợp thông thường thôi. Các bạn dẫn ra những trường hợp ngặt nghèo mà đáng lẽ một người viết code đàng hoàng không bao giờ vuớng phải.

Tôi nhắc lại: Tôi không viết cho những "người viết code đàng hoàng", vì những người có kinh nghiệm thì họ biết cách viết code. Tôi chỉ muốn ý thức cho những người chưa có nhiều kinh nghiệm thôi.

Có lẽ tôi đã nói hết ý của mình trong chủ đề này.
 
Upvote 0
@Hoàng Trọng Nghĩa:

Trong lập trình game, hoặc lập trình realtime, tốc độ là điều tất yếu. Cái này không cần phải bàn cãi.

Trong môi trường làm việc thương mãi (kế toán là một phân khoa của thương mãi), người làm còn phải cân nhắc giữa tốc độ và độ chỉnh sửa cũng như cách thức diễn giải code đi sát với lô gíc quy trình. Đối với các phần mềm đạt tính chất kiểm toán được (auditable), điều kiện sau quan trọng hơn tốc độ nhiều.

Thậm chí ở một vài nơi tôi từng hợp tác, cơ quan có chỉ thị rõ ràng là chỉ sử dụng VBA trong trường hợp không thể dùng hàm worksheet. Chỉ sử dụng CSE (array formula) khi không thể sử dụng hàm thường. Và dùng hàm phải hạn chế số dấu ngoăc "()". Vì có những luật đó nên dùng cột phụ là điều được khuyến khích. Làm quản lý một thời gian rồi sẽ thấy mục đích của luật lệ trên. Mấy cái công thức phức tạp, lúc đầu thì chạy rất ngon, lâu ngày tự dưng gặp một vài dữ liệu không thích hợp - thà nó báo lỗi thì không nói chi, gặp lúc người ta bẫy lỗi rồi đưa ra kết quả trật lất mới chết chứ. Nhiều bảng tính, mình mò cả buổi không biết con số ở đâu ra. Gặp sở thuế kiểm toán thì ủ tờ.

Lý do chính tôi đưa ra đoạn code trên là vì code nguyên thuỷ có sự lặp lại hai đoạn code in hệt nhau. Tôi chỉ đề nghị gộp lại thành một đoạn cho dễ nhìn dễ sửa. Những cái còn lại tuỳ thuộc vào trường phái sở thích riêng từng ngưòi.
 
Lần chỉnh sửa cuối:
Upvote 0
Riêng trong trường hợp của Basic muốn bàn về error thì bàn thêm như thế này:
nếu code đang nằm trong phạm vi hoạt động (scope) của định tính "On Error Resume Next" thì IF (một nhóm điều kiện) khác với IF (kiều kiện a) THEN IF (điều kiện b) ở chỗ nếu xảy ra error trong lúc xét đièu kiên a thì ở trường hợp nhóm execution engine coi như cả nhóm đạt điều kiện trong khi ở trường hợp tuần tự execution engine còn tiếp tục xét điều kiện b. Lối vận hành nào nguy hiểm hơn tuỳ theo quan niệm cá nhân.

Xét trong trường hợp bạn nói, thì sự nguy hiểm đến từ câu "On Error Resume Next", chứ không phải từ chỗ If nhóm hay nhóm If.
Do đó, bản thân tôi cũng ít khi dùng câu này. Không dùng, và test thật kỹ để sửa lỗi, hoặc bẫy lỗi, chứ không bỏ qua lỗi. Trừ khi biết chắc rằng lỗi có thể bỏ qua.

Còn đối với người mới học tại GPE đây, (bài viết tại GPE thì thành viên GPE đọc nhiều nhất), thực sự mà nói thì đa số không qua trường lớp bài bản, kể cả tôi.

Vậy nếu tôi đi trước, tôi truyền lại 1 số kính nghiệm, truyền lại 1 số lỗi tôi đã gặp, thì tốt hơn là để họ trông mong vào "bản năng hướng thiện". Ít nhất, họ có thể rút ngắn thời gian học được vài giờ. Hơn nữa, học online thì những vấn đề căn bản như "chỉ dùng IIf cho tham số literal" có mấy ai nói cho mà biết, nên họ sẽ khó mà đạt mức "thấy nguy hiểm tự động tránh"

Còn vấn đề nguy hiểm của Goto, cho đến nay tôi chưa gặp phải, (vì bản thân tôi cũng ít dùng), nhân dịp này tôi cũng muốn lắng nghe thêm, bạn vui lòng viết tiếp cặn kẽ hộ.
 
Lần chỉnh sửa cuối:
Upvote 0
Nhưng IF vẫn chưa nhanh bằng SELECT CASE.
Với nhiều điều kiện, để tăng tốc cũng như tường minh, ta nên chọn SELECT CASE.
Select Case dùng cho nhiều điều kiện khác nhau của cùng 1 tham số. Không thể dùng cho nhiều điều kiện liên quan đến 2 tham số trở lên.
 
Upvote 0
Em không biết gì về nguyên lý hoạt động của các hàm, em thường lấy dữ liệu lớn để test về thời gian, cái nào chạy đúng và nhanh em sẽ sử dụng.

Qua việc Sư phụ nhắc đến hàm IIF, trước đây em cũng đã kiểm tra, thấy nó xét tất cả các đối số TRUE, FALSE trong đó, vì thế nếu các điều kiện loại trừ trong đối số bị lỗi sẽ báo lỗi, mặt khác, nếu dùng hàm này trong một số điều kiện cụ thể với dữ liệu ít (chừng 1000 dòng) thì được, nhưng khi vài chục ngàn dòng, em đã test thì dùng IF ... THEN chạy nhanh hơn vì nó có tính rẽ nhánh, nếu nó tìm đúng, ngay lập tức thủ tục trong nó được tính toán, còn không nó chạy đến END IF tức thì.

Nhưng IF vẫn chưa nhanh bằng SELECT CASE.

Nếu như ta có For i = 1 to 10, cái ta cần giá trị từ 1 đến 8 và giá trị khác từ 9 đến 10, nếu ta dùng IF có lẽ ta viết:

If i = 1 Or i = 2 Or ... Or i = 8 Then

ElseIf i = 9 Or i = 10 Then

End If

Nếu viết như vậy thì tính hơi bị mệt!

Tuy nhiên với Select Case thì quá đơn giản, không OR hay AND gì cả:

Select Case i
Case 1 To 8
Case 9, 10
End Select


Với nhiều điều kiện, để tăng tốc cũng như tường minh, ta nên chọn SELECT CASE.

Muốn thử nghiệm thì test file này thử xem, đừng dùng mảng dể kéo dài t, từ đó sẽ rút ra nên dùng if hay and trong trường hợp này.
 

File đính kèm

Upvote 0
Kinh nghiệm của tôi, khi dùng nhiều điều kiện AND tôi phải suy luận.

Với các điều kiện A, B, C, D, ta xét như sau:

Nếu thấy: A chứa trong B, B chứa trong C, C chứa trong D

Thì ta cần xét đầu tiên đó là A, tức tập con nhỏ nhất, đến tập con lớn hơn là B, đến tập con lớn hơn là C và cuối cùng là tập mẹ D.

Vậy thì khi sử dụng tôi sẽ:

If giá trị = A AND giá trị = B AND giá trị = C AND giá trị = D Then
....
End If


Về tính logic thì "thằng nhỏ" không có thì mắc mớ gì đến "thằng lớn" sẽ có, cho nên khi xét đến AND thì chỉ 1 giá trị FALSE thì tất cả cùng FALSE vì thế nó xét giá trị đầu tiên, thấy False là nó bỏ qua, không tính thêm gì nữa.

Nhưng với cấu trúc IF ... AND ... THEN trên không hay cho lắm, tôi thường chẻ nó ra từng cặp AND với nhau:

If giá trị = A AND giá trị = B Then ....
If giá trị = C AND giá trị = D Then
....

End If
End If


Tại sao phải làm vậy? Tôi tự suy rằng nếu có nhiều đối số nó sẽ xét cái nào là AND cái nào là OR, sau đó nó xét tiếp từng biểu thức bên trong AND và OR đó. Vậy thì nếu ta xét điều kiện chủ yếu mà không có thì mắc mớ gì xét tiếp những cái còn lại, thế thì không những dài dòng văn tự mà còn bị tính cho tất cả nữa, có nên không?

Đó là kinh nghiệm mà tôi tự rút ra được sau nhiều lần thử code, còn các lập trình viên chuyên nghiệp không biết họ tính như thế nào.
 
Upvote 0
Test file thanhlanh thì phải tạo dữ liệu nhiều. Tôi test với 60 ngàn dòng:
- Code 1 If và And: 5.02 giây
- Code 2 If: 4.08 giây

Chứng tỏ nhiều If nhanh hơn 1 If nhiều And 1 chút.
 
Upvote 0
Xét trong trường hợp bạn nói, thì sự nguy hiểm đến từ câu "On Error Resume Next", chứ không phải từ chỗ If nhóm hay nhóm If.
Do đó, bản thân tôi cũng ít khi dùng câu này. Không dùng, và test thật kỹ để sửa lỗi, hoặc bẫy lỗi, chứ không bỏ qua lỗi. Trừ khi biết chắc rằng lỗi có thể bỏ qua.

Còn đối với người mới học tại GPE đây, (bài viết tại GPE thì thành viên GPE đọc nhiều nhất), thực sự mà nói thì đa số không qua trường lớp bài bản, kể cả tôi.

Vậy nếu tôi đi trước, tôi truyền lại 1 số kính nghiệm, truyền lại 1 số lỗi tôi đã gặp, thì tốt hơn là để họ trông mong vào "bản năng hướng thiện". Ít nhất, họ có thể rút ngắn thời gian học được vài giờ. Hơn nữa, học online thì những vấn đề căn bản như "chỉ dùng IIf cho tham số literal" có mấy ai nói cho mà biết, nên họ sẽ khó mà đạt mức "thấy nguy hiểm tự động tránh"

Còn vấn đề nguy hiểm của Goto, cho đến nay tôi chưa gặp phải, (vì bản thân tôi cũng ít dùng), nhân dịp này tôi cũng muốn lắng nghe thêm, bạn vui lòng viết tiếp cặn kẽ hộ.

Em xin bổ sung thêm vấn đề "On Error Resume Next"

1) Thời gian gần đây, em thường bẫy lỗi rất kỹ nên ít bao giờ thấy code của em dùng câu đó.

2) Em dùng nó trong trường hợp "bất khả kháng" như sau:

Nếu ta dùng hàm CDate, CLng, hay cDbl chẳng hạn, nếu nó quét qua dữ liệu là số thì cũng chẳng sao, nếu dữ liệu nó trộn giữa số và chuỗi thì bị "chửi rủa" lên liền!

Vậy thì phải xử lý!

Nếu đơn giản chỉ "On Error Resume Next" thì sẽ lờ qua lỗi, thế thì dữ liệu của "hàng" đó bị bỏ qua, còn nếu không dùng câu đó thì bị lỗi, phải làm sao?

Lấy lỗi "trị lỗi", Chẳng hạn:

On Error Resume Next
MyNum = cDbl(giatri)
If Err.Number = 0 then
MsgBox "Dang So"
Else
Err.Clear
MsgBox "Dang Chuoi"
End If


Nếu không dùng câu "On Error Resume Next" thì làm sao thủ tục chạy tới được thằng Else của If phải không?
 
Lần chỉnh sửa cuối:
Upvote 0
Hi hi, đừng chọc quê mình nha, test thời gian chớ gì nữa, nhưng phải nhân dữ liệu lên thật nhiều và thêm code "đo" thời gian vào, cái đó ở đây ai cũng biết mà!
Với dữ liệu trong file anh, em "nhân" lên 30,000 dòng, test thời gian gần như bằng nhau giữa 2 code
Cũng đúng, vì dữ liệu của anh nó quá đơn giản
 
Upvote 0
@Hoàng Trọng Nghĩa:


Lý do chính tôi đưa ra đoạn code trên là vì code nguyên thuỷ có sự lặp lại hai đoạn code in hệt nhau. Tôi chỉ đề nghị gộp lại thành một đoạn cho dễ nhìn dễ sửa. Những cái còn lại tuỳ thuộc vào trường phái sở thích riêng từng ngưòi.

Với bạn thì có thể trình độ cao hơn mình và nhiều người khác, nhưng thật sự khi tôi đã test thì thấy được rằng:

Trong vòng lặp, cụ thể là For ... Next đi, nếu tôi "ép" dữ liệu chỉ trong 1 vòng lặp thì điều gì sẽ xãy ra? Mỗi 1 vòng lặp nó tính n biểu thức, trong đó có những biểu thức loại trừ, nó cứ lặp đi, lặp lại cho đến hết.

Vậy tại sao ta không loại trừ trước rồi mới dùng vòng lặp sau? Có thể nhìn vào code ta thấy dùng nhiều vòng lặp, nhưng thực tế, sau khi loại trừ, thì thực sự code chạy có 1 vòng lặp thôi, còn ngược lại, với 1 vòng lặp, nhưng mỗi vòng-lặp lại lặp-lại cái loại trừ thì có phải tính toán sẽ bị chậm hơn không?

Chính vì thế, tôi chấp nhận code dài thườn thượt, nhiều vòng lặp trong mỗi biểu thức loại trừ (nhưng thực tế chỉ có chạy 1 vòng lặp khi điều kiện True), hơn là 1 vòng lặp với nhiều biểu thức loại trừ trong đó.

Đó chỉ là kinh nghiệm của tôi chứ không có tính tranh luận gì hết bạn nhé.
 
Lần chỉnh sửa cuối:
Upvote 0
Với dữ liệu trong file anh, em "nhân" lên 30,000 dòng, test thời gian gần như bằng nhau giữa 2 code
Cũng đúng, vì dữ liệu của anh nó quá đơn giản

Càng đơn giản thì sự so sánh càng chính xác, vì trong khi code chạy thì công việc chính chủ yếu là kiểm tra True và False chớ không xử lý gì khác.
 
Upvote 0
Càng đơn giản thì sự so sánh càng chính xác, vì trong khi code chạy thì công việc chính chủ yếu là kiểm tra True và False chớ không xử lý gì khác.

Chưa chắc đâu Anh, ở đây so sánh thì so sánh đồng bộ, dữ liệu đơn giản với cấu trúc đơn giản, dữ liệu phức tạp với cấu trúc phức tạp.

Mà thường người ta tính cái phức tạp, dữ liệu rất lớn để tính thời gian nhanh chậm, chứ còn đơn giản đôi khi cả 2 cái đều cho thời gian "tự làm tròn" = 0 hết cho các thời gian quá nhỏ thì làm sao biết được cao thấp chứ Anh.
 
Upvote 0
Càng đơn giản thì sự so sánh càng chính xác, vì trong khi code chạy thì công việc chính chủ yếu là kiểm tra True và False chớ không xử lý gì khác.

Nhưng trong thực tế có khi không đơn giản vậy
IF A AND B nhưng A B là kết quả của 1 quá trình tính toán phức tạp, lúc ấy so sánh mới thấy sự khác biệt
(thực tế chẳng mấy khi ta có A và B = TRUE hoặc FALSE ngay từ đầu)
 
Upvote 0
Em xin bổ sung thêm vấn đề "On Error Resume Next"

1) Thời gian gần đây, em thường bẫy lỗi rất kỹ nên ít bao giờ thấy code của em dùng câu đó.

2) Em dùng nó trong trường hợp "bất khả kháng" như sau:

Nếu ta dùng hàm CDate, CLng, hay cDbl chẳng hạn, nếu nó quét qua dữ liệu là số thì cũng chẳng sao, nếu dữ liệu nó trộn giữa số và chuỗi thì bị "chửi rủa" lên liền!

Vậy thì phải xử lý!

Nếu đơn giản chỉ "On Error Resume Next" thì sẽ lờ qua lỗi, thế thì dữ liệu của "hàng" đó bị bỏ qua, còn nếu không dùng câu đó thì bị lỗi, phải làm sao?

Lấy lỗi "trị lỗi", Chẳng hạn:

On Error Resume Next
MyNum = cDbl(giatri)
If Err.Number = 0 then
MsgBox "Dang So"
Else
Err.Clear
MsgBox "Dang Chuoi"
End If


Nếu không dùng câu "On Error Resume Next" thì làm sao thủ tục chạy tới được thằng Else của If phải không?

Có lẽ bạn tự làm khó mình rồi, chạy thử code sau:
Mã:
Sub test()
Dim mynum
mynum = 123
MsgBox VarType(mynum)
    If VarType(mynum) <> 8 Then
        mynum = CDbl(mynum)
        MsgBox VarType(mynum)
    End If
End Sub

---------------------------------------------------
BS
Mã:
Sub test2()
Dim mynum
mynum = "a"
MsgBox VarType(mynum)
    If VarType(mynum) <> 8 Then
        mynum = CDbl(mynum)
        MsgBox VarType(mynum)
    Else
        MsgBox "mynum la chuoi"
    End If
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Có lẽ bạn tự làm khó mình rồi, chạy thử code sau:

Anh lại tiểu tiết rồi! Với bài đó tôi đang nói đến chuyện KHI NÀO THÌ DÙNG "On Error Resume Next"đưa ra 1 ví dụ cụ thể trong hàng tỉ vụ bẫy lỗi như vậy. Chứ bẫy lỗi thì có quá nhiều cách, tùy người dùng cách nào mà thôi.

Ví dụ tôi đặt giá trị NGÀY mynum = "1/1/2013" hoặc tại ô A1, vì lý do nào đó người ta đặt dấu nháy (') trước ngày chẳng hạn '1/1/2013 thì VarType nó hiện lên giá trị của số nào? 7 hay 8 vậy?

Dữ liệu trên Web hay xuất từ 1 phần mềm nào đó, thì dạng ngày tháng năm thường có ký tự Chr(160) trước ngày tháng năm (cái này thường xuyên xử lý trên diễn đàn), nhưng với ?CDATE([A1]) thử trong Immediate, với A1 =CHAR(160) & "1/2/2013 3:5" thì nó vẫn cho ra kết quả là 01/02/2013 03:05:00 đấy nhé! Nhưng với VarType nó lại cho giá trị là 8 (dạng string) chứ không phải là 7 (dạng date), cho nên cái giá trị thật sự để so sánh lại bị bỏ qua.

Bởi nguồn dữ liệu đôi khi copy từ file này qua file khác, xuất từ phần mềm khác, tải từ trên mạng xuống v.v... có thể có những định dạng hỗn hợp, nên chúng ta phải lường trước nó thuộc lỗi hay không lỗi để biết mà xử lý. Còn VarType, kiểu nào cũng cho giá trị, và những giá trị đó chưa chắc đúng trường hợp cụ thể nào.
 
Lần chỉnh sửa cuối:
Upvote 0
"On Error Resume Next"

Tôi chẳng nói nên hay không nên dùng. Chỉ thấy trong một bài nọ lợi dụng đặc tính bẫy lỗi code nhét item vào dictionary cho nên tôi ngỡ cái này được mọi người chấp nhận.

(Chỉ nhớ mang máng bài ở góc VBA mà quên mất bài nào, cho nên không đưa đường dẫn được, xin lỗi)

Vả lại tôi cũng chẳng phê bình code dài. Cái tôi chỉ trích là một đoạn code lặp lại 2 lần. Cái nào tôi chỉ trích tôi nói thẳng là chỉ trích. Từ hôi biết đọc code đến giờ tôi chưa hề thấy ai biện luận lặp lại code để bảo đảm tốc độ cả. (nhưng tôi khong phải là chuyên viên, trên đời còn rất nhiều việc hay mà tôi chưa hề thấy)
 
Upvote 0
"On Error Resume Next"

Tôi chẳng nói nên hay không nên dùng. Chỉ thấy trong một bài nọ lợi dụng đặc tính bẫy lỗi code nhét item vào dictionary cho nên tôi ngỡ cái này được mọi người chấp nhận.

(Chỉ nhớ mang máng bài ở góc VBA mà quên mất bài nào, cho nên không đưa đường dẫn được, xin lỗi)

Vả lại tôi cũng chẳng phê bình code dài. Cái tôi chỉ trích là một đoạn code lặp lại 2 lần. Cái nào tôi chỉ trích tôi nói thẳng là chỉ trích. Từ hôi biết đọc code đến giờ tôi chưa hề thấy ai biện luận lặp lại code để bảo đảm tốc độ cả. (nhưng tôi khong phải là chuyên viên, trên đời còn rất nhiều việc hay mà tôi chưa hề thấy)

Tôi vẫn đang thắc mắc, tại sao không dùng Goto vậy bạn?

Theo tôi hiểu nôm na, Goto thì phải đi với một Label trong code, để giảm đi số lần lặp đi lặp lại một thủ tục khi gặp trường hợp False thì người ta Goto đến nhãn đó. Thế thì tại sao lại không dùng với các lập trình viên chuyên nghiệp?

Và xin được chỉ giáo với câu nói này:

Hàm IIF chẳng có gì phải ngại nếu dùng với literals. Bình thường thì người ta chỉ tránh dùng nó khi gọi functions:
 
Lần chỉnh sửa cuối:
Upvote 0
Lý do chính khiến Goto nên tránh (lưu ý: chỉ là 'nên' chứ không 'bắt buộc'):

Khi có lệnh goto thì các lệnh trước cái tiêu đích (label) không được bảo đảm. Ví dụ cổ điển:

code ...

goto nhảy_vài_dòng

code ...

x = 0 ' đọc code đến đây mình đinh ninh x sẽ là 0 cho đến khi được gán trị khác

nhảy_vài_dòng:

---> x ở đây chưa hẳn là 0

Kết luận: nếu mình kiểm soát được ở đâu nhảy tới label thì dễ, nhưng sau vài lần sửa đổi code tùm lum, đến chừng phải mò thì cực lắm. Mỗi lần nhìn thấy cái label là bắt buộc phải cẩn thận trị của biến.
 
Upvote 0
Lý do chính khiến Goto nên tránh (lưu ý: chỉ là 'nên' chứ không 'bắt buộc'):

Khi có lệnh goto thì các lệnh trước cái tiêu đích (label) không được bảo đảm. Ví dụ cổ điển:

code ...

goto nhảy_vài_dòng

code ...

x = 0 ' đọc code đến đây mình đinh ninh x sẽ là 0 cho đến khi được gán trị khác

nhảy_vài_dòng:

---> x ở đây chưa hẳn là 0

Kết luận: nếu mình kiểm soát được ở đâu nhảy tới label thì dễ, nhưng sau vài lần sửa đổi code tùm lum, đến chừng phải mò thì cực lắm. Mỗi lần nhìn thấy cái label là bắt buộc phải cẩn thận trị của biến.

Nói chung, ý bạn muốn nói là ngại khi kiểm tra và chỉnh sửa. Thôi thì là quan điểm của mỗi người.

==================================================

Còn vấn đề này thì sao hả bạn? Mình rất muốn biết ý đó của bạn.

Hàm IIF chẳng có gì phải ngại nếu dùng với literals. Bình thường thì người ta chỉ tránh dùng nó khi gọi functions:
 
Lần chỉnh sửa cuối:
Upvote 0
1. Goto "phá vỡ" trật tự, thứ tự của code, code trở nên rối rắm, khó hiểu, khó theo dõi, khó kiểm soát, khó tìm lỗi hơn.
2. Khi dùng goto thì cơ hội phạm lỗi sẽ lớn hơn. Điều này dễ hiểu vì code với goto rối rắm hơn nên ta dễ sơ ý, dễ không nhận thấy những vấn đề quan trọng.
3. Phân tích code có nhiều goto khó hơn nhiều do code rối rắm hơn.

Nói chung, ý bạn muốn nói là ngại khi kiểm tra và chỉnh sửa. Thôi thì là quan điểm của mỗi người.

Không hẳn như vậy. Thậm chí bạn viết cho bản thân mình mà code ngắn, dùng 1 goto thì cũng chả sao. Nhưng bạn viết một code dài hoặc có nhiều goto thì 1 năm sau quay lại tôi nghĩ rằng bạn sẽ "lạc" trong chính code của mình, và mất nhiều thời gian hơn để hiểu so với code không có goto. Còn nếu bạn làm việc trong một nhóm với 1 project lớn thì sao? Code của bạn khó hiểu thì bạn cam chịu nhưng nếu bạn đưa cái code ấy cho đồng nghiệp thì ... tôi thương xót đồng nghiệp ấy. Và code của bạn nó "khuấy động" sự hài hòa có trong project chung. Và khi cần chỉnh sửa bổ sung code thì rất khó và dễ phạm lỗi.
Không phải cấm dùng goto. Nếu 1 goto trong th đơn giản thì hoàn toàn có thể chấp nhận. Nhưng nếu có thể viết khác đi mà không dùng goto thì nên viết khác đi. Mà thường là 99% các trường hợp có thể viết khác đi mà không dùng goto.
Khi bạn đánh giá goto thì bạn làm y hệt như khi đánh giá mọi việc khác trong cuộc sống. Có nên làm cái này không? Lợi là thế này, hại là thế này. Được bằng này, mất bằng này. Rồi "hạch toán" thôi. Goto lợi ít mà hại nhiều.
Nếu bạn hỏi 100 người lập trình chuyên nghiệp, hoặc đọc 100 trang web nói về goto mà 80% nói là goto "nên tránh - nên dùng" khi có thể thì lúc đó không nên nói: "Thôi thì là quan điểm của mỗi người". Bởi vì phải có nguyên nhân gì đó nên người ta mới khuyên không nên dùng hoặc nên dùng.
 
Upvote 0
1. Goto "phá vỡ" trật tự, thứ tự của code, code trở nên rối rắm, khó hiểu, khó theo dõi, khó kiểm soát, khó tìm lỗi hơn.
2. Khi dùng goto thì cơ hội phạm lỗi sẽ lớn hơn. Điều này dễ hiểu vì code với goto rối rắm hơn nên ta dễ sơ ý, dễ không nhận thấy những vấn đề quan trọng.
3. Phân tích code có nhiều goto khó hơn nhiều do code rối rắm hơn.



Không hẳn như vậy. Thậm chí bạn viết cho bản thân mình mà code ngắn, dùng 1 goto thì cũng chả sao. Nhưng bạn viết một code dài hoặc có nhiều goto thì 1 năm sau quay lại tôi nghĩ rằng bạn sẽ "lạc" trong chính code của mình, và mất nhiều thời gian hơn để hiểu so với code không có goto. Còn nếu bạn làm việc trong một nhóm với 1 project lớn thì sao? Code của bạn khó hiểu thì bạn cam chịu nhưng nếu bạn đưa cái code ấy cho đồng nghiệp thì ... tôi thương xót đồng nghiệp ấy. Và code của bạn nó "khuấy động" sự hài hòa có trong project chung. Và khi cần chỉnh sửa bổ sung code thì rất khó và dễ phạm lỗi.
Không phải cấm dùng goto. Nếu 1 goto trong th đơn giản thì hoàn toàn có thể chấp nhận. Nhưng nếu có thể viết khác đi mà không dùng goto thì nên viết khác đi. Mà thường là 99% các trường hợp có thể viết khác đi mà không dùng goto.
Khi bạn đánh giá goto thì bạn làm y hệt như khi đánh giá mọi việc khác trong cuộc sống. Có nên làm cái này không? Lợi là thế này, hại là thế này. Được bằng này, mất bằng này. Rồi "hạch toán" thôi. Goto lợi ít mà hại nhiều.
Nếu bạn hỏi 100 người lập trình chuyên nghiệp, hoặc đọc 100 trang web nói về goto mà 80% nói là goto "nên tránh - nên dùng" khi có thể thì lúc đó không nên nói: "Thôi thì là quan điểm của mỗi người". Bởi vì phải có nguyên nhân gì đó nên người ta mới khuyên không nên dùng hoặc nên dùng.

Vâng em hiểu ý của Thầy, tuy nhiên viết code trong Excel thường là những code ngắn chừng 200 dòng là thấy giải quyết được các vấn đề. Người ta cũng khuyên, nếu code dài quá thì cắt ra từng thủ tục nhỏ, nếu đúng điều kiện thì gọi thủ tục (sub) đó (như em đã làm với hàm NewAutoFilter), thế thì ai mà viết code dài có lẽ cũng nên học cách "chia để trị" phải không Thầy?
 
Upvote 0
Vâng em hiểu ý của Thầy, tuy nhiên viết code trong Excel thường là những code ngắn chừng 200 dòng là thấy giải quyết được các vấn đề.

Thì đây là đang bàn về lập trình nói chung - goto trong các ngôn ngữ lập trình

Người ta cũng khuyên, nếu code dài quá thì cắt ra từng thủ tục nhỏ, nếu đúng điều kiện thì gọi thủ tục (sub) đó (như em đã làm với hàm NewAutoFilter), thế thì ai mà viết code dài có lẽ cũng nên học cách "chia để trị" phải không Thầy?

Không hẳn cứ dài là cắt ngắn thành thủ tục. Nhưng nếu có một loạt dòng code liên tiếp tạo thành một cụm lôgic thì có thể tách ra và gọi hàm, code sẽ dễ hiểu hơn. Hoặc khi một đoạn code lặp lại nhiều lần chỉ khác nhau về giá trị của một số biến trong mỗi lần lặp thì nên tách ra, code sẽ gọn và dễ đọc, dễ hiểu hơn.
Cũng tùy trường hợp. Nhiều khi không có lý do gì để dùng hàm nhưng có thể viết khác đi dùng các cấu trúc khác, vd. vòng lặp, thì code gọn hơn và dễ hiểu hơn.
 
Upvote 0
Vâng em hiểu ý của Thầy, tuy nhiên viết code trong Excel thường là những code ngắn chừng 200 dòng là thấy giải quyết được các vấn đề. Người ta cũng khuyên, nếu code dài quá thì cắt ra từng thủ tục nhỏ, nếu đúng điều kiện thì gọi thủ tục (sub) đó (như em đã làm với hàm NewAutoFilter), thế thì ai mà viết code dài có lẽ cũng nên học cách "chia để trị" phải không Thầy?
Nhờ các anh chị giúp em đoạn code vba change trong sheet1 công thức này với:
=IF(OR(AND(H8=66121,I8=111,M8<>"PLP"),AND(H8=334,I8=111,M8<>"PLP"),AND(M8="PLP",X8=1),AND(X8=1,H8<>111)),1,IF(OR(AND(H8=66122,I8=111,M8<>"PLP"),AND(M8="PLP",X8=1),AND(X8=2,H8<>111)),2,0))
 
Upvote 0
Nhờ các anh chị giúp em đoạn code vba change trong sheet1 công thức này với:
=IF(OR(AND(H8=66121,I8=111,M8<>"PLP"),AND(H8=334,I8=111,M8<>"PLP"),AND(M8="PLP",X8=1),AND(X8=1,H8<>111)),1,IF(OR(AND(H8=66122,I8=111,M8<>"PLP"),AND(M8="PLP",X8=1),AND(X8=2,H8<>111)),2,0))

Tôi chẳng hiểu bạn làm gì với công thức trong sheet này. Muốn gì thì bạn phải gửi cái file lên, đồng thời bạn cho một kết quả mong muốn là gì, chứ nhìn vậy chả ai giúp bạn được trọn vẹn.
 
Upvote 0
Tôi chẳng hiểu bạn làm gì với công thức trong sheet này. Muốn gì thì bạn phải gửi cái file lên, đồng thời bạn cho một kết quả mong muốn là gì, chứ nhìn vậy chả ai giúp bạn được trọn vẹn.

Em gửi file lên đây nhờ các anh chị xem giúp em viết code vba cho cột E tương ứng các giá trị với các cột kia.
 

File đính kèm

Upvote 0
Em gửi file lên đây nhờ các anh chị xem giúp em viết code vba cho cột E tương ứng các giá trị với các cột kia.

Giúp em code cho công thức Cell với file ở trên. cảm ơn các anh chị, em đã sửa lại file cần hỏi, nhờ các anh chị giúp.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Em đã sửa nội dung cần hỏi trong cell nhờ các anh chị, các bạn trên diễn đàn giúp em code vba với
 
Upvote 0
Khó Khăn Về IF trong VBA

mình đang tập làm quen với VBA mà gặp khó khăn về IF trong VBA mò mẫn mãi mà vẫn chưa ra mong các Bạn GPE trợ giúp
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, [C3:C1000]) Is Nothing Then
' If Range("E2") < 1500000 Then Code1 'Nho Hon 1,5 Trieu
' If Range("E2") > 1500000 Or Range("E2") = 15000000 Then Code2 'Lon Hon 1,5 Trieu
' If Range("E2") > 15000000 Or Range("E2") = 30000000 Then Code3 'Lon Hon 15 Trieu
' If Range("E2") > 30000000 Then Code4 'Lon Hon 30 Trieu
'**********
If Range("E2") < 1500000 Then Code1
If Range("E2") > 1500000 Then Code2
If Range("E2") > 15000000 Then Code3
If Range("E2") > 30000000 Then Code4
End If
End Sub

code mình viết nếu điều kiện tại cell E2 thay đổi. nếu E2<=1500000 thì code1 chạy và tương tự như vậy nếu E2>1.500.000 thì code2 chạy...khó khăn ở chỗ nếu E2 tăng trên 30 triệu thì thì code2,code3 và code4 điều chạy hết
Mình mong muốn nếu E2 có giá trị từ 1500.000 =>15.000.000 thì code2 chạy và E2 >15.000.000 or =30.000.000 thì code3 chạy và code4 cũng như vậy .mà chưa làm được mong các bạn trợ giúp
xin cảm ơn
Kiều Mạnh
 

File đính kèm

Upvote 0
mình đang tập làm quen với VBA mà gặp khó khăn về IF trong VBA mò mẫn mãi mà vẫn chưa ra mong các Bạn GPE trợ giúp
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, [C3:C1000]) Is Nothing Then
' If Range("E2") < 1500000 Then Code1 'Nho Hon 1,5 Trieu
' If Range("E2") > 1500000 Or Range("E2") = 15000000 Then Code2 'Lon Hon 1,5 Trieu
' If Range("E2") > 15000000 Or Range("E2") = 30000000 Then Code3 'Lon Hon 15 Trieu
' If Range("E2") > 30000000 Then Code4 'Lon Hon 30 Trieu
'**********
If Range("E2") < 1500000 Then Code1
If Range("E2") > 1500000 Then Code2
If Range("E2") > 15000000 Then Code3
If Range("E2") > 30000000 Then Code4
End If
End Sub

code mình viết nếu điều kiện tại cell E2 thay đổi. nếu E2<=1500000 thì code1 chạy và tương tự như vậy nếu E2>1.500.000 thì code2 chạy...khó khăn ở chỗ nếu E2 tăng trên 30 triệu thì thì code2,code3 và code4 điều chạy hết
Mình mong muốn nếu E2 có giá trị từ 1500.000 =>15.000.000 thì code2 chạy và E2 >15.000.000 or =30.000.000 thì code3 chạy và code4 cũng như vậy .mà chưa làm được mong các bạn trợ giúp
xin cảm ơn
Kiều Mạnh
Mã:
dim x
x=range("E2").value/1500000
If x<1 then
code1
Elseif x<10 then
code2
Elseif x<20 then
code3
Else
code4
Endif
 
Upvote 0
code như vậy có rút gọn được không...
Sub Print_out()
Dim i As Integer, j As Integer
n = Range("AO4").Value
l = Range("AP4").Value
k = Range("AN4").Value

If n > 0 And l > 0 And k > 0 And l > n Then

For i = l To n Step -1
Range("AB4").Value = i
Range("Q4").Value = k
ActiveWindow.SelectedSheets.PrintOut 1, 1, 1, False, False

Next i
End If

n = Range("AO4").Offset(1, 0).Value
l = Range("AP4").Offset(1, 0).Value
k = Range("AN4").Offset(1, 0).Value

If n > 0 And l > 0 And k > 0 And l > n Then

For i = l To n Step -1
Range("AB4").Value = i
Range("Q4").Value = k
ActiveWindow.SelectedSheets.PrintOut 1, 1, 1, False, False
Next i
End If


End Sub
 

File đính kèm

Upvote 0
code như vậy có rút gọn được không...
Sub Print_out()
Dim i As Integer, j As Integer
n = Range("AO4").Value
l = Range("AP4").Value
k = Range("AN4").Value

If n > 0 And l > 0 And k > 0 And l > n Then

For i = l To n Step -1
Range("AB4").Value = i
Range("Q4").Value = k
ActiveWindow.SelectedSheets.PrintOut 1, 1, 1, False, False

Next i
End If

n = Range("AO4").Offset(1, 0).Value
l = Range("AP4").Offset(1, 0).Value
k = Range("AN4").Offset(1, 0).Value

If n > 0 And l > 0 And k > 0 And l > n Then

For i = l To n Step -1
Range("AB4").Value = i
Range("Q4").Value = k
ActiveWindow.SelectedSheets.PrintOut 1, 1, 1, False, False
Next i
End If


End Sub
Có thể sửa ngắn hơn chút nửa.
Mã:
Sub Print_out()
    Dim i As Integer, n As Integer, l As Integer, k As Integer
        n = Range("AO4").Value
        l = Range("AP4").Value
        k = Range("AN4").Value
     
    If Min(n, l, k) > 0 And l > n Then
   
        For i = l To n Step -1
            Range("AB4").Value = i
            Range("Q4").Value = k
            Sheet1.PrintOut 1, 1, 1, 0, 0
        Next i
     End If
     
        n = Range("AO5").Value
        l = Range("AP5").Value
        k = Range("AN5").Value
   
    If Min(n, l, k) > 0 And l > n Then
       
        For i = l To n Step -1
            Range("AB4").Value = i
            Range("Q4").Value = k
            Sheet1.PrintOut 1, 1, 1, 0, 0
        Next i
    End If
   
End Sub
Theo tôi thấy code của bạn có những chổ chưa hợp lý, còn chổ nào thì bạn tự tìm hiểu nhé.
 
Upvote 0
Có thể sửa ngắn hơn chút nửa.
Mã:
Sub Print_out()
    Dim i As Integer, n As Integer, l As Integer, k As Integer
        n = Range("AO4").Value
        l = Range("AP4").Value
        k = Range("AN4").Value
   
    If Min(n, l, k) > 0 And l > n Then
 
        For i = l To n Step -1
            Range("AB4").Value = i
            Range("Q4").Value = k
            Sheet1.PrintOut 1, 1, 1, 0, 0
        Next i
     End If
   
        n = Range("AO5").Value
        l = Range("AP5").Value
        k = Range("AN5").Value
 
    If Min(n, l, k) > 0 And l > n Then
     
        For i = l To n Step -1
            Range("AB4").Value = i
            Range("Q4").Value = k
            Sheet1.PrintOut 1, 1, 1, 0, 0
        Next i
    End If
 
End Sub
Theo tôi thấy code của bạn có những chổ chưa hợp lý, còn chổ nào thì bạn tự tìm hiểu nhé.
Có thể sửa ngắn hơn chút nửa.
Mã:
Sub Print_out()
    Dim i As Integer, n As Integer, l As Integer, k As Integer
        n = Range("AO4").Value
        l = Range("AP4").Value
        k = Range("AN4").Value
    
    If Min(n, l, k) > 0 And l > n Then
  
        For i = l To n Step -1
            Range("AB4").Value = i
            Range("Q4").Value = k
            Sheet1.PrintOut 1, 1, 1, 0, 0
        Next i
     End If
    
        n = Range("AO5").Value
        l = Range("AP5").Value
        k = Range("AN5").Value
  
    If Min(n, l, k) > 0 And l > n Then
      
        For i = l To n Step -1
            Range("AB4").Value = i
            Range("Q4").Value = k
            Sheet1.PrintOut 1, 1, 1, 0, 0
        Next i
    End If
  
End Sub
Theo tôi thấy code của bạn có những chổ chưa hợp lý, còn chổ nào thì bạn tự tìm hiểu nhé.
Mình cũng thấy có chổ chưa hợp lý nhưng tìm hoài chưa thông, trong trường hợp này mình chỉ lặp có 2 vòng cho 2 dòng dữ liệu, nếu lặp n vòng thì chẳng lẽ copy cả mớ code ^^.
 
Upvote 0
Mã:
Sub Print_out()
InCaiGiDo "AO4", "AP4", "AN4"
InCaiGiDo "AO5", "AP5", "AN5"
End Sub

Sub InCaiGiDo(ByVal vn As String, ByVal vl As String, ByVal vk As String)
Dim i As Integer, n As Integer, l As Integer, k As Integer
n = Range(vn).Value
l = Range(vl).Value
k = Range(vk).Value
If Min(n, l, k) > 0 And l > n Then
    For i = l To n Step -1
        Range("AB4").Value = i
        Range("Q4").Value = k
        Sheet1.PrintOut 1, 1, 1, 0, 0
    Next i
 End If
End Sub

Sub Print_out_CaDong() ' in cả đống
Dim i As Long
For i = 4 To 5 ' thay 5 bằng dòng cuối cùng
InCaiGiDo "AO" & i, "AP" & i, "AN" & i
Next i
End Sub

Tôi chỉ mách cho cách thu gọn thôi. Còn những chỗ hợp lý hay phi lý tôi không màng tới. Code mà không có chú thích thì tự nó đã rối rắm rồi.
 
Upvote 0
Mã:
Sub Print_out()
InCaiGiDo "AO4", "AP4", "AN4"
InCaiGiDo "AO5", "AP5", "AN5"
End Sub

Sub InCaiGiDo(ByVal vn As String, ByVal vl As String, ByVal vk As String)
'khai báo biến chổ này mình không hiểu
Dim i As Integer, n As Integer, l As Integer, k As Integer
n = Range(vn).Value
l = Range(vl).Value
k = Range(vk).Value
If Min(n, l, k) > 0 And l > n Then
' đoạn này bị báo lỗi " Sub or Funtion not defined"
    For i = l To n Step -1
        Range("AB4").Value = i
'in từ trang n đến trang l
        Range("Q4").Value = k
'giá trị trong ô "Q4=AN4" không đổi khi i thay đổi từ n đến l
        Sheet1.PrintOut 1, 1, 1, 0,
'khi in xong từ n đến l ô "Q4=AN5" không đổi, i thay đổi theo n đến l tức là dòng kế tiếp "AO5" "AP5"
    Next i
End If
End Sub

Sub Print_out_CaDong() ' in cả đống
Dim i As Long
For i = 4 To 5 ' thay 5 bằng dòng cuối cùng
InCaiGiDo "AO" & i, "AP" & i, "AN" & i
Next i
End Sub

Tôi chỉ mách cho cách thu gọn thôi. Còn những chỗ hợp lý hay phi lý tôi không màng tới. Code mà không có chú thích thì tự nó đã rối rắm rồi.
Có thể sửa ngắn hơn chút nửa.
Mã:
Sub Print_out()
    Dim i As Integer, n As Integer, l As Integer, k As Integer
        n = Range("AO4").Value
        l = Range("AP4").Value
        k = Range("AN4").Value
  
    If Min(n, l, k) > 0 And l > n Then

        For i = l To n Step -1
            Range("AB4").Value = i
            Range("Q4").Value = k
            Sheet1.PrintOut 1, 1, 1, 0, 0
        Next i
     End If
  
        n = Range("AO5").Value
        l = Range("AP5").Value
        k = Range("AN5").Value

    If Min(n, l, k) > 0 And l > n Then

    
        For i = l To n Step -1
            Range("AB4").Value = i
            Range("Q4").Value = k
            Sheet1.PrintOut 1, 1, 1, 0, 0
        Next i
    End If

End Sub
Theo tôi thấy code của bạn có những chổ chưa hợp lý, còn chổ nào thì bạn tự tìm hiểu nhé.
cám ơn bạn đã góp ý, nhưng mà đoạn code này mình có vài chổ chưa hiểu bạn giúp mình nhé
Sub Print_out()
InCaiGiDo "AO4", "AP4", "AN4"
InCaiGiDo "AO5", "AP5", "AN5"
End Sub

Sub InCaiGiDo(ByVal vn As String, ByVal vl As String, ByVal vk As String)
'khai báo biến chổ này mình không hiểu
Dim i As Integer, n As Integer, l As Integer, k As Integer
n = Range(vn).Value
l = Range(vl).Value
k = Range(vk).Value
If Min(n, l, k) > 0 And l > n Then
' đoạn này bị báo lỗi " Sub or Funtion not defined"
For i = l To n Step -1
Range("AB4").Value = i
'in từ trang n đến trang l
Range("Q4").Value = k
'giá trị trong ô "Q4=AN4" không đổi khi i thay đổi từ n đến l
Sheet1.PrintOut 1, 1, 1, 0,
'khi in xong từ n đến l ô "Q4=AN5" không đổi, i thay đổi theo n đến l tức là dòng kế tiếp "AO5" "AP5"
Next i
End If
End Sub

Sub Print_out_CaDong() ' in cả đống
Dim i As Long
For i = 4 To 5 ' thay 5 bằng dòng cuối cùng
InCaiGiDo "AO" & i, "AP" & i, "AN" & i
Next i
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
cám ơn bạn đã góp ý, nhưng mà đoạn code này mình có vài chổ chưa hiểu bạn giúp mình nhé
Tôi chỉ thâu ngắn nó lại chứ nào có hiểu code nó làm cái gì đâu mà giải thích.
Code của bạn từ đầu không giải thích thì bảo người khác giải thích giùm à?
 
Upvote 0
Tôi chỉ thâu ngắn nó lại chứ nào có hiểu code nó làm cái gì đâu mà giải thích.
Code của bạn từ đầu không giải thích thì bảo người khác giải thích giùm à?
Diễn đàn toàn pro không, mình thấy đoạn code bé tẹo này chắc các bạn có thể giúp mình ý mà, nhưng mà trong đoạn trên mình có giải thích lại rồi mà bạn
 
Upvote 0
Định mệnh...mấy thánh giỏi quá, em làm dc rồi, thanks bác VetMini nhé
 
Upvote 0

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

Back
Top Bottom