Các câu đố, bài tập nhằm ôn tập & bổ sung kiến thức căn bản VBA

Liên hệ QC

Hoàng Trọng Nghĩa

Chuyên gia GPE
Thành viên BQT
Moderator
Tham gia
17/8/08
Bài viết
8,662
Được thích
16,720
Giới tính
Nam
Với tinh thần chơi mà học, học mà chơi, nên tôi đã mở ra topic này, hy vọng các thành viên tham gia, nhất là các thành viên mới biết về VBA.

Sau đây là câu hỏi đầu tiên:

Câu hỏi 1: Bằng phương pháp nào nhanh nhất để tìm ra ô nào trong một cột chứa một điều kiện.

Tôi có 1 file Excel 2007, với cột A, từ A1 đến A1048576 đều có giá trị.

Bằng phương pháp nào nhanh nhất (dùng mảng, dùng For Each v.v...) để tìm ra ô nào trong cột A chứa chữ "Nghia", đồng thời với ô ở cột B tương ứng nhập giá trị "OK" vào đó?

Ví dụ tìm thấy trong ô A2 có giá trị là "Nghia" thì ô B2 nhập vào "OK".

Hiện tại, đáp án nhanh nhất mà tôi có được đã gửi mail riêng (nhằm ghi lại thời gian gửi, để tránh nói ăn gian).

Để tiện việc theo dõi các câu đố, các bài tập tôi đã tạo ra topic này các bạn click vào đây:

Các link của topic "Các câu đố, bài tập nhằm ôn tập & bổ sung kiến thức căn bản VBA"
 

File đính kèm

Lần chỉnh sửa cuối:
Thay vì như thế, sao không viết như thế này để nó bớt tính toán nhỉ?

If UCase(j) = "A" Or UCase(j) = "B" Or UCase(j) = "C" Or UCase(j) = "D"
Vì mình định viết theo dạng tổng quát mà, tên Sp đâu chỉ có 1 chữ (trong bài này là vd thế thôi)
Bài khác mà Vd Range("A3")= "Main Engine" chẳng nhẽ viết UCase(j) = "MAIN ENGINE", viết thế này thôi Ucase(j) = Ucase(Range("A3"))


KHÔNG CÓ GÌ MÀ PHẢI SỢ NGƯỜI TA CƯỜI. CỨ VIẾT THEO MÌNH HIỂU. TÔI CŨNG ĐANG HỌC BẠN ĐẤY THÔI.
HÌNH NHƯ CODE CỦA BẠN BIẾN i TÔI CHẢ THẤY BẠN SỬ DỤNG CHỖ NÀO
Sorry vì copy code của phanminhphuong quên ko bỏ biến i vì không sử dụng vòng lặp.
có ai thử sử dụng code tạo PivotTable rồi lấy kết quả cho bài này ko? Cho mình tham khảo tí
 
Lần chỉnh sửa cuối:
Upvote 0
Vì mình định viết theo dạng tổng quát mà, tên Sp đâu chỉ có 1 chữ (trong bài này là vd thế thôi)
Bài khác mà Vd Range("A3")= "Main Engine" chẳng nhẽ viết UCase(j) = "MAIN ENGINE", viết thế này thôi Ucase(j) = Ucase(Range("A3"))
Đúng thế, nhưng tùy trường hợp mà áp dụng cụ thể bạn hen!

hiện tại có 4 cột thì dim 4 cái store. vậy có 10 cột chắc lại phải viết khác rồi đúng không thầy. lúc đó lại store &n phải không ạ

"Được voi là đòi hai bà Trưng" liền à! Dĩ nhiên sẽ có nhiều phương pháp để tính, nhưng hiện tại, chỉ nên biết vậy thôi hen!
 
Upvote 0
Đúng thế, nhưng tùy trường hợp mà áp dụng cụ thể bạn hen!



"Được voi là đòi hai bà Trưng" liền à! Dĩ nhiên sẽ có nhiều phương pháp để tính, nhưng hiện tại, chỉ nên biết vậy thôi hen!
tạm thời lấy cái chân voi cái đã. còn 3 chân kia khi nào lấy được rồi sẽ tìm bà trưng sau
PHP:
Private Sub CommandButton1_Click()
    Dim store1 As Long, store2 As Long, store3 As Long, store4 As Long, I As Long
    Dim Kho As String, Rng As Range
ComeBack:
    Kho = LCase(InputBox("Ban chon loai san pham nao?" & vbLf & "(a,b,c,d)", "Chon loai"))
     Select Case Kho
    Case "a", "b", "c", "d"
        Set Rng = Sheet4.Range("A3:A16")
        For I = 1 To Rng.Rows.Count
            If LCase(Rng(I)) = Kho Then
                store1 = store1 + Rng(I, 2)
                store2 = store2 + Rng(I, 3)
                store3 = store3 + Rng(I, 4)
                store4 = store4 + Rng(I, 5)
            End If
        Next I
        MsgBox "Tong doanh so mat hang " & Kho & ":" _
                & vbLf & "- Store 01: " & Format(store1, "#,###") _
                & vbLf & "- Store 02: " & Format(store2, "#,###") _
                & vbLf & "- Store 03: " & Format(store3, "#,###") _
                & vbLf & "- Store 04: " & Format(store4, "#,###") _
                , , "Ket qua"
    Case Else
        If MsgBox("Ban chon khong dung hoac khong chon ten san pham nao!" & vbLf & _
        "Ban co muon chon lai khong?", vbYesNo + vbQuestion, "Thông báo") = vbYes Then
            GoTo ComeBack
        End If
    End Select
End Sub
 
Upvote 0
Nếu Sư phụ nói Arr() là biến mảng, và cũng nói nếu không khai báo kiểu thì có giá trị Empty là không chính xác!
Xin kiểm chứng cho Code này:
Mã:
Sub test()
    Dim sArr
    Dim Arr()
    MsgBox IsEmpty(sArr)
    MsgBox IsEmpty(Arr)
End Sub
Như vậy, biến sArr không khai báo, mặc nhiên nó là một biến Variant, thì nó mới chính là có giá trị Empty!

Nghĩa đang nhầm lẫn 2 việc:
1. Tôi không nói đến biến variant. Sarr hay Staolao gì, nếu không khai báo kiểu thì nó là variant là đương nhiên.
2. Tôi nói giá trị của biến, chứ tôi không nói isEmty của biến

Ngoài ra:

3. Code do chính Nghĩa viết, vậy Nghĩa đã chạy chưa? Dẹp sArr và STaolao qua 1 bên, MsgBox IsEmpty(Arr) cho giá trị True hay False? Nếu False thì Arr có Empty không? (Câu này sai)

Tôi phải nói thêm:

1. Một biến mảng không có giá trị riêng, nếu dùng MsgBox Arr thì sẽ báo lỗi.
2. Giá trị của mảng là tập hợp các giá trị của các phần tử của nó
3. Chỉ các phần tử của mảng mới có giá trị riêng. Do đó có thể MsgBox Arr(1)
4. Kể cả khi biến mảng đã được gán giá trị cho tất cả các phần tử, IsEmpty của nó vẫn False, tức là nó vẫn Empty:

Thí dụ:

Mã:
Sub abc()
  Dim Arr(1 To 3)
   Arr(1) = 1
   Arr(2) = 2
   Arr(3) = 3
MsgBox IsEmpty(Arr) 'Ket qua False
End Sub
(Mục số 4 sai)

Còn giá trị ban đầu của biến mảng có phải Empty không, thì hãy xem hình. Ghi chú là xem lại (1) và (2): Giá trị của mảng là tập hợp các giá trị các phần tử của mảng
Hình này chứng tỏ là giá trị của phần tử của mảng Arr(2) khi chưa gán gì là Empty.

 
Lần chỉnh sửa cuối:
Upvote 0
tạm thời lấy cái chân voi cái đã. còn 3 chân kia khi nào lấy được rồi sẽ tìm bà trưng sau
PHP:
Private Sub CommandButton1_Click()
    Dim store1 As Long, store2 As Long, store3 As Long, store4 As Long, I As Long
    Dim Kho As String, Rng As Range
ComeBack:
    Kho = LCase(InputBox("Ban chon loai san pham nao?" & vbLf & "(a,b,c,d)", "Chon loai"))
     Select Case Kho
    Case "a", "b", "c", "d"
        Set Rng = Sheet4.Range("A3:A16")
        For I = 1 To Rng.Rows.Count
            If LCase(Rng(I)) = Kho Then
                store1 = store1 + Rng(I, 2)
                store2 = store2 + Rng(I, 3)
                store3 = store3 + Rng(I, 4)
                store4 = store4 + Rng(I, 5)
            End If
        Next I
        MsgBox "Tong doanh so mat hang " & Kho & ":" _
                & vbLf & "- Store 01: " & Format(store1, "#,###") _
                & vbLf & "- Store 02: " & Format(store2, "#,###") _
                & vbLf & "- Store 03: " & Format(store3, "#,###") _
                & vbLf & "- Store 04: " & Format(store4, "#,###") _
                , , "Ket qua"
    Case Else
        If MsgBox("Ban chon khong dung hoac khong chon ten san pham nao!" & vbLf & _
        "Ban co muon chon lai khong?", vbYesNo + vbQuestion, "Thông báo") = vbYes Then
            GoTo ComeBack
        End If
    End Select
End Sub


Bạn hiền tuyệt lắm! Rất hợp với ý mình! Không cần dùng vòng lặp Do ... Loop để bẫy lỗi là như thế! Great!

Dùng Select Case trong bài toán này là rất chuẩn!
 
Lần chỉnh sửa cuối:
Upvote 0
Nghĩa đang nhầm lẫn 2 việc:
1. Tôi không nói đến biến variant. Sarr hay Staolao gì, nếu không khai báo kiểu thì nó là variant là đương nhiên.
2. Tôi nói giá trị của biến, chứ tôi không nói isEmty của biến

Ngoài ra:

3. Code do chính Nghĩa viết, vậy Nghĩa đã chạy chưa? Dẹp sArr và STaolao qua 1 bên, MsgBox IsEmpty(Arr) cho giá trị True hay False? Nếu False thì Arr có Empty không?

Tôi phải nói thêm:

1. Một biến mảng không có giá trị riêng, nếu dùng MsgBox Arr thì sẽ báo lỗi.
2. Giá trị của mảng là tập hợp các giá trị của các phần tử của nó
3. Chỉ các phần tử của mảng mới có giá trị riêng. Do đó có thể MsgBox Arr(1)
4. Kể cả khi biến mảng đã được gán giá trị cho tất cả các phần tử, IsEmpty của nó vẫn False, tức là nó vẫn Empty:

Thí dụ:

Mã:
Sub abc()
  Dim Arr(1 To 3)
   Arr(1) = 1
   Arr(2) = 2
   Arr(3) = 3
MsgBox IsEmpty(Arr) 'Ket qua False
End Sub

Còn giá trị ban đầu của biến mảng có phải Empty không, thì hãy xem hình. Ghi chú là xem lại (1) và (2): Giá trị của mảng là tập hợp các giá trị các phần tử của mảng
Hình này chứng tỏ là giá trị của phần tử của mảng Arr(2) khi chưa gán gì là Empty.



IsArray(Biến) = True thì nó chính là Array, IsNumeric(Biến) = True thì nó chính là dạng Number, cũng vậy, IsEmpty(Biến) = True, thì nó chính là Empty chứ sao Sư phụ hỏi lạ vậy?**~**

Mà sao Sư phụ có thể làm Sub đó phát sinh ra lỗi cũng đặc biệt thật luôn! Em thử hoài mà nó không ra lỗi!

Mã:
Sub KhongHieu()
    Dim Arr(3)
    Arr(0) = 1
    Arr(1) = 2
    Arr(2) = 3
    Arr(3) = 4
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
hiện tại có 4 cột thì dim 4 cái store. vậy có 10 cột chắc lại phải viết khác rồi đúng không thầy. lúc đó lại store &n phải không ạ

Lúc đó dùng biến mảng Store(1 to 10)
Sau đó dùng vòng lặp con bên trong vòng For ngoài:

PHP:
For j = 1 to 10
Store(j) = Store(j) + Rng(I).Offset(, j)
Next
 
Lần chỉnh sửa cuối:
Upvote 0
IsArray(Biến) = True thì nó chính là Array, IsNumeric(Biến) = True thì nó chính là dạng Number, cũng vậy, IsEmpty(Biến) = True, thì nó chính là Empty chứ sao Sư phụ hỏi lạ vậy?**~**

Chỗ này tôi nhầm.
IsEmty(Arr) = False nghĩa là Arr() không phải Empty.

Tuy nhiên điều này có nghĩa là nó có chứa phần tử bên trong nó chứ không phải "giá trị của nó không phải empty". Còn giá trị các phần tử vẫn là Empty như bài trên tôi có thí dụ và chụp hình.
 
Upvote 0
Upvote 0
Upvote 0
Nếu Sư phụ nói Arr() là biến mảng, và cũng nói nếu không khai báo kiểu thì có giá trị Empty là không chính xác!

Xin kiểm chứng cho Code này:

Mã:
Sub test()
    Dim sArr
    Dim Arr()
    MsgBox IsEmpty(sArr)
    MsgBox IsEmpty(Arr)
End Sub

Như vậy, biến sArr không khai báo, mặc nhiên nó là một biến Variant, thì nó mới chính là có giá trị Empty!
Thay vì test như vậy, ta test kiểu khác xem:
Mã:
Sub test()
    Dim sArr
    Dim Arr()
    MsgBox TypeName(sArr)
    MsgBox TypeName(Arr)
End Sub
Ẹc... Ẹc... --=0
-------------
Mà chắc sư phụ Mỹ đang nói đến các phần tử trong mảng chứ không phải nói nguyên 1 mảng?
 
Lần chỉnh sửa cuối:
Upvote 0
Mà sao Sư phụ có thể làm Sub đó phát sinh ra lỗi cũng đặc biệt thật luôn! Em thử hoài mà nó không ra lỗi!

Đoạn code đó để chụp hình giá trị Arr(2) = Empty thôi.
Nếu thêm câu lệnh này mới lỗi: Msgbox Arr() hoặc MsgBox Arr (tôi cũng ghi rất rõ mà? Kể cả câu tôi sai tôi cũng ghi rất rõ.)

Mà quý vị vui lòng trích dẫn ít thôi, trích cả đoạn code dài lê thê làm gì, đọc mệt quá. Với lại, nếu hỏi thêm thì viết bài mới, đừng edit bài cũ có khi tôi không đọc lại.
 
Upvote 0
Nhưng ít ra nó cũng rất đẹp và sáng code phải không Sư phụ!

Với bài này thì OK.
Tuy nhiên là một người mới tìm hiểu VBA nhưng mình thấy nên hạn chế tối đa sử dụng Goto vì những nhược điểm của nó như trong một bài viết của anh Siwtom
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.
Vì vậy đối với những người chập chững/ tìm hiểu căn bản VBA như mình xin vui lòng hướng dẫn và chia sẻ tỉ mỉ, rõ ràng hơn những kinh nghiệm đó. Tks
 
Lần chỉnh sửa cuối:
Upvote 0
Nhưng ít ra nó cũng rất đẹp và sáng code phải không Sư phụ!

Cái này không đúng nha!
Lập trình chuyên nghiệp tối kỵ Goto. Dù là người mới thì cũng nên hướng cho họ đi theo "hướng tốt"
Nghĩa cho rằng Goto là "sáng" và "đẹp" thì.. coi chừng... Ẹc... Ẹc...
 
Upvote 0
Thay vì test như vậy, ta test kiểu khác xem:
Ẹc... Ẹc... --=0

Việc test này nhằm kiểm tra giá trị của mảng có phải Empty hay không mà. Như tôi đã nói, mảng không có giá trị riêng, mà là tập hợp các giá trị của các phần tử.
Mảng không Empty vì nó chứa các phần tử, nhưng giá trị ban đầu của các phần tử sẽ là Empty.
 
Upvote 0
thông thường khi lập trình (tôi thường sử dụng C++) thì người ta thường dùng vòng lập để cho người ta nhập theo ý muốn của đề. rất ít khi thấy người ta dùng nhãn lắm
code của bạn tôi đã sửa lại theo những gì tôi hiểu và cũng đã test không thấy gì sai cả. nếu nhập không đúng abcd thì nó cũng thoát nếu người dùng bấm ok hay cancel lần 2.nói như bác siwtom. phải cho người ta cơ hội nhập lại chứ
tôi vẫn thích bạn dùng loop until
 
Lần chỉnh sửa cuối:
Upvote 0
thông thường khi lập trình (tôi thường sử dụng C++) thì người ta thường dùng vòng lập để cho người ta nhập theo ý muốn của đề. rất ít khi thấy người ta dùng nhãn lắm
Đúng là vậy, mỗi người làm theo quan điểm của mình, nếu không phát sinh lỗi và sáng code, dễ nhìn, dễ hiểu đặc biệt là phải hiệu quả, chính xác là OK. Tùy thói quen vậy!
 
Upvote 0
code của bạn tôi đã sửa lại theo những gì tôi hiểu và cũng đã test không thấy gì sai cả. nếu nhập không đúng abcd thì nó cũng thoát nếu người dùng bấm ok hay cancel lần 2.nói như bác siwtom. phải cho người ta cơ hội nhập lại chứ

Ý người ta nói hạn chế Goto thôi, đâu ai nói code sai
--------------------
Khẳng định: THÓI QUEN GOTO là thói quen XẤU. Không tin Nghĩa có thể search khắp google mà hỏi thử
--------------------
Một cái Goto chẳng nói gì. Thử tưởng tượng trong code có vài chục cái goto thì lúc test code chẳng biết đâu mà lần
Ngày trước khi mới tập tành, code tôi goto cả đống. Bây giờ rảnh rỗi mở ra phải sửa lại hết (vì nó khó theo dõi chứ chắng có "sáng" tí nào cả)
 
Lần chỉnh sửa cuối:
Upvote 0
...
Cho em hỏi luôn là Chr(10) & Chr(13) đều là ngắt xuống dòng, là một hay có gì khác nhau? Xin vui lòng giải thích

Nói trước. Ai không muốn nghe nói chuyện rườm rà thì bỏ qua, đừng đọc tiếp.

Bạn có thấy cái bàn máy đánh chữ thời thượng cổ qua chưa?

Trên bàn máy, có một cái trục cuốn giấy. Khi gõ một ký tự, trục này chạy về bên trái một nấc, lộ chỗ cho bạn gõ ký tự kế tiếp. Khi muốn sang dòng mới, hoặc khi chạy hết giới hạn về bên trái, tức là bạn đã gõ đủ một dòng, bạn phải kéo một cái cần cho trục này đi trở ngược về phía phải. Và đồng thời trục cuốn giấy lên một dòng. Kết quả là bạn sẽ tiếp tục gõ ở đầu dòng mới.

Cái trục này tên là "carriage". Động tác chạy về đầu dòng gọi là "carriage return", viết tắt là CR. Động tác cuốn lên dòng mới gọi là "line feed", viết tắt LF.

Trong quy ước ASCII, LF có giá trị 10 và CR giá trị 13.

Theo quy ước máy in thời thượng cổ, để sang một dòng mới cần phải có cả CR lẫn LF. Tuy nhiên phải tùy theo hệ thống mà người ta đặt CR trước hay LF trước.

Về sau này, các hệ điều hành mới có khi chỉ dùng một trong 2.

Vì vậy, các phần mềm mới có khuynh hướng dùng hằng số NewLine để tránh nói thẳng là CR hay LF. Các phần mềm xịn khi nạp qua các hệ điều hành khác nhau thì hệ thống tự đông thay đổi hằng số.

Tức là, theo nguyên tắc thì nên dùng NewLine hơn CR hay LF hay CRLF. Trên thực tế thì... tôi không rõ ông VBA theo tiêu chuẩn đến mức nào nên không dám nói thêm.

Thêm:

Khổng tử hỏi: Người trí là người thế nào, người nhân là người thế nào
Nhan hồi trả lời: Người trí là người biết mình, người nhân là người thương mình

Tánh tôi rất thương cái "tôi" của mình. Tôi lên diễn đàn mà không cho tôi nói về cái tôi của mình thì tôi cụt cả hứng. Mà đã cụt hứng thì tự giải vấn đề của mình còn bậy bạ nữa huống hồ gì của người khác.
 
Upvote 0
Web KT

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

Back
Top Bottom