Chú ý: Các thành viên học lớp "Lập trình VBA trong Excel" có thể trao đổi bài ở đây (2 người xem)

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

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

Đó là anh chưa tính khoản giảm trừ cho bản thân người nộp thuế 4 triệu. Nếu không có người phụ thuộc thì không được trừ gì hết, nhưng nếu có người phụ thuộc sẽ được giảm 2 khoản:
- 4 tr cho bản thân người nộp thuế
- 1.6 tr cho mỗi người phụ thuộc
Cho nên người phải nộp không có người phụ thuộc phải nộp: 5.000.000*0.05+1.400.000*0.1=390.000
Còn người kia tính khoản giảm trừ thì thu nhập thực chịu thuế là 8.000.000-4.000.000-1*1.600.000=2.400.000
Do đó thực nộp chỉ là 2.400.000*0.05=120.000 thôi.

Mình đang nói trên file của bạn ra mà : E7 nhập 6.400.000 F7 nhập 0 G7 =390000 (sai)
G6 = 120000 Đúng
 
Đây là bài về xếp loại học sinh của em (Cách xếp loại là em tự nghĩ ra, có gì sai anh Nghĩa bỏ qua cho nhé)
Mã:
Option Explicit

Function XepLoai(ByVal iDiemToan As Integer, ByVal iDiemLy As Integer, ByVal iDiemHoa As Integer) As String
Dim lTB As Long
lTB = (iDiemToan + iDiemLy + iDiemHoa) / 3
Select Case lTB
    Case Is >= 8
        If iDiemToan >= 7 And iDiemLy >= 7 And iDiemHoa >= 7 Then
            XepLoai = "Gioi"
        Else
            XepLoai = "Kha"
        End If
    Case Is >= 7
        If iDiemToan >= 5 And iDiemLy >= 5 And iDiemHoa >= 5 Then
            XepLoai = "Kha"
        Else
            XepLoai = "Trung Binh"
        End If
    Case Is >= 5
        If iDiemToan >= 4 And iDiemLy >= 4 And iDiemHoa >= 4 Then
            XepLoai = "Trung Binh"
        Else
            XepLoai = "Yeu"
        End If
    Case Is < 5
            XepLoai = "Yeu"
End Select
End Function
 

File đính kèm

Lần chỉnh sửa cuối:
Chết thật! Em cũng sơ xuất quá, em lại không test mức >85 triệu chứ!!? Giờ em test lại mới thấy không đúng rồi.
Bác Công phát hiện đúng rồi đó.
Code của Anh Sealand sửa lại đoạn này mới đúng:
Mã:
Case Is > 80
Tncn1 = 0.35 * dTnhap -[COLOR=red] 18.15[/COLOR]
Sửa thành
Mã:
 Tncn1 = 0.35 * dTnhap - 9.85
 

File đính kèm

File đính kèm

Lần chỉnh sửa cuối:
Có AC nào làm bài hàm tìm min có điều kiện chưa? Em làm được hàm max nhưng thay dấu > bằng dấu < để làm hàm min thì toàn bị giá trị là 0
Mã:
Function MyMinIf(ByVal rngVungTest As Range, ByVal GiaTriTest As Variant, ByVal rngVungSoLieu As Range) As Long
    Dim i As Long
    Dim lSoHang As Long
    lSoHang = rngVungTest.Rows.Count
        For i = 1 To lSoHang
            If rngVungTest(i) = GiaTriTest And rngVungSoLieu(i) < MyMinIf Then
                MyMinIf = rngVungSoLieu(i)
            End If
        Next i
End Function
 
Có AC nào làm bài hàm tìm min có điều kiện chưa? Em làm được hàm max nhưng thay dấu > bằng dấu < để làm hàm min thì toàn bị giá trị là 0
Bạn thử với cái ni xem ra răng, chừ?

PHP:
Option Explicit
Function MyMinIf(ByVal rngVungTest As Range, ByVal GiaTriTest As Variant, ByVal rngVungSoLieu As Range) As Long
 Dim i As Long, lSoHang As Long
 
 lSoHang = rngVungTest.Rows.Count
 For i = 1 To lSoHang
   If rngVungTest(i) = GiaTriTest And rngVungSoLieu(i) < MyMinIf Then
      MyMinIf = rngVungSoLieu(i)
   Else
      MsgBox MyMinIf, , rngVungSoLieu(i)
   End If
 Next i
End Function
 
Lần chỉnh sửa cuối:
Có vấn đề gì đấy mình chưa hiểu ra. Cái bài này http://www.giaiphapexcel.com/forum/group.php?do=discuss&discussionid=12&pp=10&page=2
Hàm MyMax thì được, nhưng đổi dấu > và < rồi nhưng hàm MyMIN thì lại không được

Ngoài chuyện đổi dầu, ta còn fải đổi trị nữa:

(*) Bạn có biết vào dòng lệnh đầu tiên MyMAX của bạn có trị là bao nhiêu không vậy?

Còn hàm MyMIN thì dòng lệnh đầu tiên được thêm là:

MyMIN= 2147483647

thì sẽ OK ngay tấp lự! Hãy thử & tìm nguyên nhân nha!


(*) MyMAX của bạn sẽ tầm bậy tầm bạ, nếu cột số liệu toàn âm đó nha!

Các bạn quên rằng kiểu dữ liệu Long có 1 nữa trong nó là số bé hơn không; & đừng quên chúng chứ!
 
Ngoài chuyện đổi dầu, ta còn fải đổi trị nữa:

(*) Bạn có biết vào dòng lệnh đầu tiên MyMAX của bạn có trị là bao nhiêu không vậy?

Còn hàm MyMIN thì dòng lệnh đầu tiên được thêm là:

MyMIN= 2147483647

thì sẽ OK ngay tấp lự! Hãy thử & tìm nguyên nhân nha!


(*) MyMAX của bạn sẽ tầm bậy tầm bạ, nếu cột số liệu toàn âm đó nha!

Các bạn quên rằng kiểu dữ liệu Long có 1 nữa trong nó là số bé hơn không; & đừng quên chúng chứ!

Bác ah! Em theo lời bác làm đúng như vầy là Ok

Option Explicit

Function MyMin(ByVal rngNum As Range) As Double
Dim MyCell As Range
MyMin = 2147483647
For Each MyCell In rngNum
If MyCell.Value < MyMin Then
MyMin = MyCell.Value
End If
Next
End Function
''================================================================
Function MyMax(ByVal rngNum As Range) As Double
Dim MyCell As Range
MyMax = -2147483647
For Each MyCell In rngNum
If MyCell.Value > MyMax Then
MyMax = MyCell.Value
End If
Next
End Function


Em thấy kiểu Long nhận giá trị từ - 2147483647 đến 2147483647 vậy nó có liên quan như thế nào đến MyMax = - 2147483647
mà ở đây hàm khai báo là kiểu Double.

*Tại sao lại thế? Nhờ bác giảng hộ em và các bạn với.
 
Em thấy kiểu Long nhận giá trị từ - 2147483647 đến 2147483647 vậy nó có liên quan như thế nào đến MyMax = - 2147483647
mà ở đây hàm khai báo là kiểu Double.
À rất mừng là bạn đã truy ra chuỗi số dài ngoãng kia nó từ đâu mà ra!

Còn mình lấy số đó là căn cứ vô hàm viết ở #108, ở đấy khai báo kiểu Long;

Thực ra sau này ta nhờ hàm MAX() /MIN() trong excel để ấn định thì chắc ăn hơn;

VD MyMAX = Application.WorkSheetFunction(MIN(rngMyRange)-9))
 
Em cũng xin tham gia 1 vi dụ nhỏ về bài học vòng lặp nha:

PHP:
Private Function TimTen(ByVal rngVung As Range) As String
    Dim rngCell As Range
    Set rngVung = Worksheets("Sheet2").Range("TEN") 'Vung B1:C10 minh dat bang TEN do
    For Each rngCell In rngVung
        If rngCell = "NGOC" Then
            TimTen = rngCell.Value
        End If
    Next
    Set rngVung = Nothing
End Function
 

File đính kèm

Ngoài chuyện đổi dầu, ta còn fải đổi trị nữa:

(*) Bạn có biết vào dòng lệnh đầu tiên MyMAX của bạn có trị là bao nhiêu không vậy?

Còn hàm MyMIN thì dòng lệnh đầu tiên được thêm là:

MyMIN= 2147483647

thì sẽ OK ngay tấp lự! Hãy thử & tìm nguyên nhân nha!


(*) MyMAX của bạn sẽ tầm bậy tầm bạ, nếu cột số liệu toàn âm đó nha!

Các bạn quên rằng kiểu dữ liệu Long có 1 nữa trong nó là số bé hơn không; & đừng quên chúng chứ!

Bác cho em hỏi nhé: Tại sao MyMIN= 2147483647? Em cứ nghĩ mãi mà không biết ý nghĩa của nó? Tai sao lại phai bằng 1 số cụ thể đó? Mà khi trong vùng tính có giá trị nó vẫn tính được?
Và, cũng như vậy nếu tím giá trị Mã?
Bác tư vấn dùm em nha!!
Thank you very much!
 
Tại sao MyMIN= 2147483647? Em cứ nghĩ mãi mà không biết ý nghĩa của nó? Tai sao lại phai bằng 1 số cụ thể đó? Mà khi trong vùng tính có giá trị nó vẫn tính được?
Và, cũng như vậy nếu tím giá trị Max?
VuMinh tìm ra rồi đó nha, khi nào hỏi bạn ấy thử xem!

Nhân đây đề nghị các bạn nào trong lớp học rảnh rỗi viết dùm hàm MAXIF(rngVùng As Range,strCriteria As String)

để tìm trong Excel 2003 doanh số cực trị của 1 mã hàng nào đó.

Ma|DoanhThu
GPE01|10^3
GPE09|10^4
GPE01|123 456
GPE05|10^5
GPE09|987 654
GPE05|555 555
. . |. .

Chúc lớp học thành công mỹ mãn!
 
Lần chỉnh sửa cuối:
Em cũng xin tham gia 1 vi dụ nhỏ về bài học vòng lặp nha:

PHP:
Private Function TimTen(ByVal rngVung As Range) As String
    Dim rngCell As Range
    Set rngVung = Worksheets("Sheet2").Range("TEN") 'Vung B1:C10 minh dat bang TEN do
    For Each rngCell In rngVung
        If rngCell = "NGOC" Then
            TimTen = rngCell.Value
        End If
    Next
    Set rngVung = Nothing
End Function
Chà mới học đặt name áp dụng liền ta. Thêm 1 cách nữa không dùng vòng lặp đây
Mã:
Private Function TimTen1(ByVal rngVung As Range) As String
 Dim rngCell As Range
  Set rngVung = Worksheets("Sheet2").Range("TEN") 'Vung B1:C10 minh dat bang TEN do
    If Not rngVung.Find("NGOC", , xlValues, xlWhole) Is Nothing Then
        TimTen1 = "NGOC"
    End If
  Set rngVung = Nothing
End Function
 
VuMinh tìm ra rồi đó nha, khi nào hỏi bạn ấy thử xem!

Nhân đây đề nghị các bạn nào trong lớp học rảnh rỗi viết dùm hàm MAXIF(rngVùng As Range,strCriteria As String)

để tìm trong Excel 2003 doanh số cực trị của 1 mã hàng nào đó.

Ma|DoanhThu
GPE01|10^3
GPE09|10^4
GPE01|123 456
GPE05|10^5
GPE09|987 654
GPE05|555 555
. . |. .

Chúc lớp học thành công mỹ mãn!

Em chỉ hiểu được nếu MyMin= 2147483647 thì ô tìm có giá trị nhỏ nhất trong vùng nó khôn được lớn hơn MyMin (nếu lớn hơn không thoả mãn).
 
Em cũng xin tham gia 1 vi dụ nhỏ về bài học vòng lặp nha:

PHP:
Private Function TimTen(ByVal rngVung As Range) As String
    Dim rngCell As Range
    Set rngVung = Worksheets("Sheet2").Range("TEN") 'Vung B1:C10 minh dat bang TEN do
    For Each rngCell In rngVung
        If rngCell = "NGOC" Then
            TimTen = rngCell.Value
        End If
    Next
    Set rngVung = Nothing
End Function

Chà mới học đặt name áp dụng liền ta. Thêm 1 cách nữa không dùng vòng lặp đây
Mã:
Private Function TimTen1(ByVal rngVung As Range) As String
 Dim rngCell As Range
  Set rngVung = Worksheets("Sheet2").Range("TEN") 'Vung B1:C10 minh dat bang TEN do
    If Not rngVung.Find("NGOC", , xlValues, xlWhole) Is Nothing Then
        TimTen1 = "NGOC"
    End If
  Set rngVung = Nothing
End Function

Viết hàm (Function) là để dùng trên sheet hoặc dùng trong các thủ tục/ hàm khác. Hàm có tham số của hàm, trong bài trên là tham số rngVung, tham số này lấy 1 vùng từ bảng tính (As Range mà).
Thế mà trong hàm lại cố định rngVung là "Ten" (B1:C10), rồi tìm 'Ngoc" trong vùng đó. Thế là dù cho dùng hàm bao nhiêu lần, ở bất kỳ đâu, cũng đều cho 1 kết quả như nhau:
- hoặc là "Ngọc" nếu có "Ngoc" trong B1:C10,
- hoặc là lỗi nếu không có
Ngoài ra, nếu người dùng gõ: =TimTen1(D1:D10), nó cũng đi tìm trong B1:C10! Chứ không tìm trong vùng D1:D10 mà ngừoi dùng muốn.
 
Lần chỉnh sửa cuối:
VuMinh tìm ra rồi đó nha, khi nào hỏi bạn ấy thử xem!

Nhân đây đề nghị các bạn nào trong lớp học rảnh rỗi viết dùm hàm MAXIF(rngVùng As Range,strCriteria As String)

để tìm trong Excel 2003 doanh số cực trị của 1 mã hàng nào đó.
Chúc lớp học thành công mỹ mãn![/B][/I][/COLOR]
Em xin đưa cách lập hàm MaxIf bằng cách tìm tất cả các cells có chứa mã cần tính đưa vào 1 biến tạm sau đó dùng hàm Max. Code của Em như sau, mong Thầy và các Anh xem góp ý cho Em nhé!
Mã:
Private Function MaxIf(rngVung_ma As Range, sCriteria As String)
  Dim tmp(1 To 65500, 1 To 1), Clls As Range, jR As Long
    For Each Clls In rngVung_ma
        If Clls.Value = sCriteria Then
            jR = jR + 1
            tmp(jR, 1) = Clls.Offset(, 1)
        End If
    Next
  MaxIf = WorksheetFunction.Max(tmp)
End Function
 

File đính kèm

Viết hàm (Function) là để dùng trên sheet hoặc dùng trong các thủ tục/ hàm khác. Hàm có tham số của hàm, trong bài trên là tham số rngVung, tham số này lấy 1 vùng từ bảng tính (As Range mà).
Thế mà trong hàm lại cố định rngVung là "Ten" (B1:C10), rồi tìm 'Ngoc" trong vùng đó. Thế là dù cho dùng hàm bao nhiêu lần, ở bất kỳ đâu, cũng đều cho 1 kết quả như nhau:
- hoặc là "Ngọc" nếu có "Ngoc" trong B1:C10,
- hoặc là lỗi nếu không có
Ngoài ra, nếu người dùng gõ: =TimTen1(D1:D10), nó cũng đi tìm trong B1:C10! Chứ không tìm trong vùng D1:D10 mà ngừoi dùng muốn.

Tại em đang muốn vận dụng cái Name nên em mặc định đường dẫn như vậy mà?
Em cám ơ ý kiến đóng góp của anh Mỹ nha!
 
Tại em đang muốn vận dụng cái Name nên em mặc định đường dẫn như vậy mà?
Em cám ơ ý kiến đóng góp của anh Mỹ nha!

Viết 1 code để vận dụng cái gì đó, thì ít nhất cũng nên nghĩ đến việc ứng dụng 1 chút. Thí dụ viết hàm để tìm 1 tên nào đó có trong danh sách có sẵn hay không.
Thí dụ:

PHP:
Private Function TimTen(ByVal SName As String) As String
 Dim rngCell As Range, VungDS As Range
  Set VungDS = Worksheets("Sheet2").Range("TEN") 
  TimTen = "Khong"
    For Each rngCell In VungDS
        If rngCell = SName Then
            TimTen = "Co"
        End If
    Next
  Set VungDS = Nothing
End Function
 
Em xin đưa cách lập hàm MaxIf bằng cách tìm tất cả các cells có chứa mã cần tính đưa vào 1 biến tạm sau đó dùng hàm Max. Code của Em như sau, mong Thầy và các Anh xem góp ý cho Em nhé!
Mã:
Private Function MaxIf(rngVung_ma As Range, sCriteria As String)
  Dim tmp(1 To 65500, 1 To 1), Clls As Range, jR As Long
    For Each Clls In rngVung_ma
        If Clls.Value = sCriteria Then
            jR = jR + 1
            tmp(jR, 1) = Clls.Offset(, 1)
        End If
    Next
  MaxIf = WorksheetFunction.Max(tmp)
End Function

Cám ơn bác đã đóng ghóp ý kiến cho các thành viên trong lớp.
Nhưng bọn e vẫn chưa học về biến tạm bác ạh.
qua đây bác nói qua qua cho bọn em chút được không?
 
Cám ơn bác đã đóng ghóp ý kiến cho các thành viên trong lớp.
Nhưng bọn e vẫn chưa học về biến tạm bác ạh.
qua đây bác nói qua qua cho bọn em chút được không?
Đấy là phương pháp dùng mảng, hơi trừu tượng 1 chút ---> Các bạn mới học tốt nhất không cần nghĩ đến làm gì cho mệt óc ---> Cứ làm theo lối suy nghĩ bình thường là được rồi
 
Thầy và các Anh cho Em hỏi, Em có ý tưởng lập hàm Maxif bằng cách AutoFilter sau đó dùng hàm Subtotal để tìm giá trị lớn nhất. Em viết như sau:
Mã:
Private Function MaxIf(rngVung_ma As Range, sCriteria As String)
  With rngVung_ma.Resize(, 1)
    .AutoFilter (1), Criteria1:=sCriteria
    MaxIf = WorksheetFunction.Subtotal(104, [COLOR=red].Select[/COLOR])
    .AutoFilter
  End With
End Function
Sao nó lại báo lỗi nhỉ? Cái chỗ .Select Em phải thay như thế nào?
 
Lần chỉnh sửa cuối:
Thầy và các Anh cho Em hỏi, Em có ý tưởng lập hàm Maxif bằng cách AutoFilter sau đó dùng hàm Subtotal để tìm giá trị lớn nhất. Em viết như sau:
Mã:
Private Function MaxIf(rngVung_ma As Range, sCriteria As String)
  With rngVung_ma.Resize(, 1)
    .AutoFilter (1), Criteria1:=sCriteria
    MaxIf = WorksheetFunction.Subtotal(104, [COLOR=red].Select[/COLOR])
    .AutoFilter
  End With
End Function
Sao nó lại báo lỗi nhỉ? Cái chỗ .Select Em phải thay như thế nào?
Viết hàm theo kiểu này, nếu dùng được thì có họa chăng chỉ áp dụng cho code khác mà thôi (tức 1 đoạn code nào đó ứng dụng hàm này) ---> Nếu gõ trên bảng tính, ăn chắc 100% chẳng ra kết quả gì (hoặc báo lỗi)
Lý do vì: Những hàm tự tạo viết với mục đích gõ trên bảng tính chỉ làm nhiệm vụ tính toán rồi ra kết quả... Nó không có khả năng thay đổi bất cứ thứ gì trên bảng tính cả (chẳng hạn như Format Cells, AutoFiler, Advanced Filer...vân vân...)
 
Em vẫn chưa hiểu tại sao trong bài lập hàm MinIf mà hàm khai báo kiểu Double mà lại cần có MyMin = 2147483647. Các AC giải thích giúp dùm em được không ah?
 
Em vẫn chưa hiểu tại sao trong bài lập hàm MinIf mà hàm khai báo kiểu Double mà lại cần có MyMin = 2147483647. Các AC giải thích giúp dùm em được không ah?

Hàm MinIf và MaxIf là tìm giá trị nhỏ nhất, lớn nhất theo điều kiện nào đó. Lưu ý, giá trị nhỏ nhất và giá trị lớn nhất phải nằm trong vùng dữ liệu được chọn.
 
Em vẫn chưa hiểu tại sao trong bài lập hàm MinIf mà hàm khai báo kiểu Double mà lại cần có MyMin = 2147483647. Các AC giải thích giúp dùm em được không ah?
Cái này chỉ làm hàm tìm giá trị MIN khai báo MyMin = 2147483647 không phải hàm MinIf tìm giá trị nhỏ nhất theo điều kiện.
Tại sao lại phải có dãy số MyMin = 2147483647 và (MyMax = - 2147483647) mình vẫn chưa được rõ chỗ này (#111 và #112). Nhưng nếu ko khai báo thì KQ sẽ bị sai khi tìm giá trị MIN và MAX nếu trong vùng toàn là số âm (Làm như Code VD trên lớp) tôi đã test lại rùi. Đúng như bac HYEN17 đã nêu xem #111
 
Tại sao lại phải có dãy số MyMin = 2147483647 và (MyMax = - 2147483647) mình vẫn chưa được rõ chỗ này (#111 và #112). Nhưng nếu ko khai báo thì KQ sẽ bị sai khi tìm giá trị MIN và MAX nếu trong vùng toàn là số âm (Làm như Code VD trên lớp) tôi đã test lại rùi.

Khi khai báo biến, bạn cần chú ý phạm vi biến có thể nhận giá trị. Ví dụ như:

Byte Store integer values in the range of 0 - 255
Integer Store integer values in the range of (-32,768) - (+ 32,767)
Long Store integer values in the range of (- 2,147,483,468) - (+ 2,147,483,468)
Single Store floating point value in the range of (-3.4x10-38) - (+ 3.4x1038)

Vì vậy, khi tìm giá trị nhỏ nhất (MyMin) thì ta cứ gán nó bằng giá trị lớn nhất (chính là dãy số mà bạn hỏi đó, có thể giá trị đó chưa được chính xác lắm) mà nó có thể có. Sau đó dùng vòng lặp so sánh để tìm được giá trị nhỏ nhất. Trường hợp lớn nhất thì làm ngược lại.

Theo tôi, nên hạn chế sử dụng các hàm sẵn có trong Excel (Worksheet Functions) vì là đặc thù riêng của Excel, nếu muốn phát triển hơn thì nên tự xây dựng hàm cho mình bằng kiến thức lập trình.

VD như bạn tìm người trẻ nhất trong danh sách thì đầu tiên gán MyMin = 150 tuổi đã (coi là tuổi khó có ai đạt được), sau đó dùng vòng lặp nếu ai kém hơn thì gán MyMin bằng tuổi đó ---> từ đó tìm được tuổi trẻ nhất.
 
Lần chỉnh sửa cuối:
Cái này chỉ làm hàm tìm giá trị MIN khai báo MyMin = 2147483647 không phải hàm MinIf tìm giá trị nhỏ nhất theo điều kiện.
Tại sao lại phải có dãy số MyMin = 2147483647 và (MyMax = - 2147483647) mình vẫn chưa được rõ chỗ này (#111 và #112). Nhưng nếu ko khai báo thì KQ sẽ bị sai khi tìm giá trị MIN và MAX nếu trong vùng toàn là số âm (Làm như Code VD trên lớp) tôi đã test lại rùi. Đúng như bac HYEN17 đã nêu xem #111

Code trên lớp chỉ là ví dụ đơn giản về thuật toán. Hình như mọi người đang bị sai về hai hàm này. Hãy gán giá trị đầu tiên ở đầu danh sách, chứ không phải các số 21...., -21.....
 
[ Nguyên văn bởi vuminh1601
Cái này chỉ làm hàm tìm giá trị MIN khai báo MyMin = 2147483647 không phải hàm MinIf tìm giá trị nhỏ nhất theo điều kiện.
Tại sao lại phải có dãy số MyMin = 2147483647 và (MyMax = - 2147483647) mình vẫn chưa được rõ chỗ này (#111 và #112). Nhưng nếu ko khai báo thì KQ sẽ bị sai khi tìm giá trị MIN và MAX nếu trong vùng toàn là số âm (Làm như Code VD trên lớp) tôi đã test lại rùi. Đúng như bac HYEN17 đã nêu xem #111
Code trên lớp chỉ là ví dụ đơn giản về thuật toán. Hình như mọi người đang bị sai về hai hàm này. Hãy gán giá trị đầu tiên ở đầu danh sách, chứ không phải các số 21...., -21.....
.]
thầy ơi, nhưng vấn đề là tại sao khi mình làm hàm mymax thì ko cần gán giá trị đầu danh sách còn làm hàm mymin thì phải gán ah? em ko hiểu nguyên nhân vì sao? thầy giải thích hộ em ah.
 
thầy ơi, nhưng vấn đề là tại sao khi mình làm hàm mymax thì ko cần gán giá trị đầu danh sách còn làm hàm mymin thì phải gán ah? em ko hiểu nguyên nhân vì sao? thầy giải thích hộ em ah.
Theo lý giải của các thầy cộng thêm việc test thử với 1 giá trị âm trong vùng thì em có thể lý giải là lúc đầu máy sẽ chạy tự động từ giá trị nhỏ nhất ( tức - 2147483647) đến giá trị lớn nhất (2147483647), suy ra hàm MyMax không cần đặt giá trị. Còn với hàm MyMin, nếu tất cả giá trị trong vùng âm thì mặc nhiên nó sẽ lớn hơn 0 và máy sẽ chọn giá trị nhỏ nhất là 0, còn nếu ta đặt 1 số âm trong đó thì số âm sẽ được chọn là min. Nếu ta đặt giá trị MyMin =2147483647, tức là giá trị tới hạn của kiểu long thì máy sẽ bắt buộc phải chạy từ lớn về nhỏ, do vậy sẽ tìm được giá trị nhỏ nhất.
Đây chỉ là suy luận chủ quan của em. Mong mọi người cho ý kiến.
Tuy vậy em vẫn còn thắc mắc là tại sao máy không chọn giá trị tới hạn kiểu Double hoặc Single mặc dù hàm khai báo theo kiểu Double, do vậy nếu giá trị cần so sánh nhỏ hơn - 2147483647 hoặc lớn hơn 2147483647 thì sẽ tìm thế nào? Em đã thử giá trị trong 1 cell là 214748399999 thì hàm MyMax báo lỗi #VALUE
 
Lần chỉnh sửa cuối:
Hàm MyMin, MyMax

Đây là đáp án về hàm MyMin, MyMax. Còn MyMinIf, MyMaxIf các bạn có thể viết trên cơ sở đáp án này.

Mã:
Function MyMax(ByVal rngNum As Range) As Double
    Dim MyCell As Range
    MyMax = rngNum.Cells(1, 1).Value
    For Each MyCell In rngNum
        If MyCell.Value > MyMax Then
            MyMax = MyCell.Value
        End If
    Next
End Function

Function MyMin(ByVal rngNum As Range) As Double
    Dim MyCell As Range
    MyMin = rngNum.Cells(1, 1).Value
    For Each MyCell In rngNum
        If MyCell.Value < MyMin Then
            MyMin = MyCell.Value
        End If
    Next
End Function
 
Anh Tuân à, nếu dùng hàm IIf() sẽ gọn hơn cấu trúc If....End if :

Mã:
Function MyMin1(ByVal rngNum As Range) As Double
    Dim MyCell As Range
    MyMin1 = rngNum.Cells(1, 1).Value
    For Each MyCell In rngNum
    MyMin1 = IIf(MyCell.Value < MyMin1, MyCell, MyMin1)
    Next
End Function
'------------------------------------------------------------------------
Function MyMax1(ByVal rngNum As Range) As Double
    Dim MyCell As Range
    MyMax1 = rngNum.Cells(1, 1).Value
    For Each MyCell In rngNum
    MyMax1 = IIf(MyCell.Value > MyMax1, MyCell, MyMax1)
    Next
End Function
 
Anh Tuân à, nếu dùng hàm IIf() sẽ gọn hơn cấu trúc If....End if :

Mã:
Function MyMin1(ByVal rngNum As Range) As Double
    Dim MyCell As Range
    MyMin1 = rngNum.Cells(1, 1).Value
    For Each MyCell In rngNum
    MyMin1 = IIf(MyCell.Value < MyMin1, MyCell, MyMin1)
    Next
End Function
'------------------------------------------------------------------------
Function MyMax1(ByVal rngNum As Range) As Double
    Dim MyCell As Range
    MyMax1 = rngNum.Cells(1, 1).Value
    For Each MyCell In rngNum
    MyMax1 = IIf(MyCell.Value > MyMax1, MyCell, MyMax1)
    Next
End Function

Vâng, đúng vậy anh ạ. hàm IIF chỉ dùng để nhận giá trị đơn, còn If..Then thì nhận khối lệnh. Vì thế tùy từng trường hợp dùng IIF hay If..Then.
Vì lớp học này các học viên chưa học một hàm nào mà đang học ngôn ngữ nên chưa dùng hàm. Sau khi học ngôn ngữ ổn rồi thì chuyển sang học các hàm và các đối tượng Excel.

Vì tại sao chúng em cho bài tập viết hàm MyMin, MyMax mặc dù Excel cái này rồi. Cái học viên có được từ bài tập này đó là cách viết UDF - hàm người dùng trên bảng tính, biết hơn về thuật toán, từ đây tiến tới các thuật toán sắp xếp, ...

Cảm ơn anh đã chia sẻ.
 
Dựa trên cơ sở hàm MyMax và MyMin của Thầy Tuân, Em viết 2 hàm MyMaxIf và MyMinIF như sau:
Mã:
Function MyMaxIf(ByVal rngVung_ma As Range, ByVal sCriteria As String, ByVal rngNum As Range) As Double
  Dim iR As Long, enR As Long
  enR = rngNum.Rows.Count
  MyMaxIf = Application.WorksheetFunction.Min(rngNum)
    For iR = 1 To enR
        If (rngVung_ma.Cells(iR, 1).Value = sCriteria) And (rngNum.Cells(iR, 1).Value > MyMaxIf) Then
            MyMaxIf = rngNum.Cells(iR, 1).Value
        End If
    Next
End Function
'-----------------------------------------------------------------------------------------------
Function MyMinIf(ByVal rngVung_ma As Range, ByVal sCriteria As String, ByVal rngNum As Range) As Double
  Dim iR As Long, enR As Long
  enR = rngNum.Rows.Count
  MyMinIf = Application.WorksheetFunction.Max(rngNum)
    For iR = 1 To enR
        If (rngVung_ma.Cells(iR, 1).Value = sCriteria) And (rngNum.Cells(iR, 1).Value < MyMinIf) Then
            MyMinIf = rngNum.Cells(iR, 1).Value
        End If
    Next
End Function
 
Dựa trên cơ sở hàm MyMax và MyMin của Thầy Tuân, Em viết 2 hàm MyMaxIf và MyMinIF như sau:
Mã:
Function MyMaxIf(ByVal rngVung_ma As Range, ByVal sCriteria As String, ByVal rngNum As Range) As Double
  Dim iR As Long, enR As Long
  enR = rngNum.Rows.Count
  MyMaxIf = Application.WorksheetFunction.Min(rngNum)
    For iR = 1 To enR
        If (rngVung_ma.Cells(iR, 1).Value = sCriteria) And (rngNum.Cells(iR, 1).Value > MyMaxIf) Then
            MyMaxIf = rngNum.Cells(iR, 1).Value
        End If
    Next
End Function
'-----------------------------------------------------------------------------------------------
Function MyMinIf(ByVal rngVung_ma As Range, ByVal sCriteria As String, ByVal rngNum As Range) As Double
  Dim iR As Long, enR As Long
  enR = rngNum.Rows.Count
  MyMinIf = Application.WorksheetFunction.Max(rngNum)
    For iR = 1 To enR
        If (rngVung_ma.Cells(iR, 1).Value = sCriteria) And (rngNum.Cells(iR, 1).Value < MyMinIf) Then
            MyMinIf = rngNum.Cells(iR, 1).Value
        End If
    Next
End Function

Không dùng bất kỳ hàm nào trong WorksheetFunction nhé. MinhCong thử làm cách khác xem thế nào.
 
Dựa trên cơ sở hàm MyMax và MyMin của Thầy Tuân, Em viết 2 hàm MyMaxIf và MyMinIF như sau:
Mã:
Function MyMaxIf(ByVal rngVung_ma As Range, ByVal sCriteria As String, ByVal rngNum As Range) As Double
  Dim iR As Long, enR As Long
  enR = rngNum.Rows.Count
  MyMaxIf = Application.WorksheetFunction.Min(rngNum)
    For iR = 1 To enR
        If (rngVung_ma.Cells(iR, 1).Value = sCriteria) And (rngNum.Cells(iR, 1).Value > MyMaxIf) Then
            MyMaxIf = rngNum.Cells(iR, 1).Value
        End If
    Next
End Function
'-----------------------------------------------------------------------------------------------
Function MyMinIf(ByVal rngVung_ma As Range, ByVal sCriteria As String, ByVal rngNum As Range) As Double
  Dim iR As Long, enR As Long
  enR = rngNum.Rows.Count
  MyMinIf = Application.WorksheetFunction.Max(rngNum)
    For iR = 1 To enR
        If (rngVung_ma.Cells(iR, 1).Value = sCriteria) And (rngNum.Cells(iR, 1).Value < MyMinIf) Then
            MyMinIf = rngNum.Cells(iR, 1).Value
        End If
    Next
End Function
Nếu dùng đến hàm MAX và MIN, thôi thà gõ trực tiếp lên bảng tính luôn cho xong ----> Nếu có ý định mai này dùng vào những ứng dụng khác thì tạm thời quên các hàm Excel đi
Ít ra cũng phải vầy:
PHP:
Function MaxIf(CritRng As Range, Criteria, ResRng As Range) As Double
  Dim TmpMax As Double, i As Long, j As Long
  TmpMax = -9.99999999999999E+307
  For i = 1 To CritRng.Rows.Count
    For j = 1 To CritRng.Columns.Count
      If CritRng(i, j) = Criteria Then
        If ResRng(i, j) > TmpMax Then TmpMax = ResRng(i, j).Value
      End If
    Next
  Next
  MaxIf = TmpMax
End Function
PHP:
Function MinIf(CritRng As Range, Criteria, ResRng As Range) As Double
  Dim TmpMin As Double, i As Long, j As Long
  TmpMin = 9.99999999999999E+307
  For i = 1 To CritRng.Rows.Count
    For j = 1 To CritRng.Columns.Count
      If CritRng(i, j) = Criteria Then
        If ResRng(i, j) < TmpMin Then TmpMin = ResRng(i, j).Value
      End If
    Next
  Next
  MinIf = TmpMin
End Function
Khi viết hàm nên tổng quát 1 chút ---> Phải dùng được với 1 vùng 1 cột nhiều dòng hoặc 1 dòng nhiều cột (thậm chí là 1 vùng nhiều cột nhiều dòng cũng chơi luôn)
Tổng quát hơn nữa thì phải vầy:
PHP:
Function MaxIf(ByVal CritArr, ByVal Criteria, ByVal ResArr) As Double
  Dim TmpMax As Double, TmpCrit, TmpRes, i As Long, j As Long
  TmpMax = -9.99999999999999E+307
  TmpCrit = CritArr: TmpRes = ResArr
  For i = LBound(TmpCrit, 1) To UBound(TmpCrit, 1)
    For j = LBound(TmpCrit, 2) To UBound(TmpCrit, 2)
      If TmpCrit(i, j) = Criteria Then
        If TmpRes(i, j) > TmpMax Then TmpMax = TmpRes(i, j)
      End If
    Next
  Next
  MaxIf = TmpMax
End Function
PHP:
Function MinIf(ByVal CritArr, ByVal Criteria, ByVal ResArr) As Double
  Dim TmpMin As Double, TmpCrit, TmpRes, i As Long, j As Long
  TmpMin = 9.99999999999999E+307
  TmpCrit = CritArr: TmpRes = ResArr
  For i = LBound(TmpCrit, 1) To UBound(TmpCrit, 1)
    For j = LBound(TmpCrit, 2) To UBound(TmpCrit, 2)
      If TmpCrit(i, j) = Criteria Then
        If TmpRes(i, j) < TmpMin Then TmpMin = TmpRes(i, j)
      End If
    Next
  Next
  MinIf = TmpMin
End Function
Không hề quan tâm đến Range luôn... Khéo léo, có thể kết hợp 2 hàm này làm 1, chẳng hạn:
PHP:
Function SummaryIf(ByVal CritArr, ByVal Criteria, ByVal ResArr, ByVal FuncType As String) As Double
  '.......................
End Function
Tìm MAX hay MIN sẽ dựa vào tham số FuncType ---> Đại khái thế
 
Lần chỉnh sửa cuối:
Em nộp bài MyMaxIf ạ!!!
Mã:
Function MyMaxIf(ByVal rngTest As Range, _
                 ByVal TestValue As Variant, _
                 ByVal rngValue As Range) As Double
    Dim i As Long
    Dim lCountRows As Long
        MyMaxIf = -2147483648#
        lCountRows = rngTest.Rows.Count
    For i = 1 To lCountRows
        If rngTest(i).Value = TestValue Then
            If MyMaxIf < rngValue(i).Value Then
                MyMaxIf = rngValue(i).Value
            End If
        End If
    Next i
End Function
 

File đính kèm

Lần chỉnh sửa cuối:
Em nộp bài MyMaxIf ạ!!!
Mã:
Function MyMaxIf(ByVal rngTest As Range, _
                 ByVal TestValue As Variant, _
                 ByVal rngValue As Range) As Double
    Dim i As Long
    Dim lCountRows As Long
        MyMaxIf = -2147483648#
        lCountRows = rngTest.Rows.Count
    For i = 1 To lCountRows
        If rngTest(i).Value = TestValue Then
            If MyMaxIf < rngValue(i).Value Then
                MyMaxIf = rngValue(i).Value
            End If
        End If
    Next i
End Function
Thế hàm này chỉ làm việc được với vùng dữ liệu 1 cột nhiều dòng thôi hả bạn?
Trường hợp dữ liệu của tôi thế này thì sao?

untitled.JPG
 
Thế hàm này chỉ làm việc được với vùng dữ liệu 1 cột nhiều dòng thôi hả bạn?
Trường hợp dữ liệu của tôi thế này thì sao?

View attachment 54430

Thầy ơi, mới học VBA mấy bạn như vậy là cố gắng lắm rồi ạ! Hàm của Thầy em học trên diễn đàn này hơn 3 năm còn chưa hiểu huống chi mấy bạn mới! Thầy làm với Level thấp thôi để cho em và mọi thành viên mới cùng học chứ cao quá hỏng có hiểu!

Cám ơn Thầy!
 
Thầy ơi, mới học VBA mấy bạn như vậy là cố gắng lắm rồi ạ! Hàm của Thầy em học trên diễn đàn này hơn 3 năm còn chưa hiểu huống chi mấy bạn mới! Thầy làm với Level thấp thôi để cho em và mọi thành viên mới cùng học chứ cao quá hỏng có hiểu!

Cám ơn Thầy!
Chính vì mới học nên tôi mong muốn các bạn có hướng suy nghĩ thêm về những khả năng cải tiến của hàm mình viết ra (không phải cứ ra kết quả đúng là tưởng nó ngon rồi nha)
Không bắt các bạn phải 1 bước lên mây ngay, nhưng ít ra cũng đừng tự hài lòng về những gì ta đã làm được! Thế thôi mà...
Ẹc... Ẹc...
-----------------
Có đại ca MOD nào đi ngang qua đây vui lòng "bứng" ông #142 đi giùm cái
 
Lần chỉnh sửa cuối:
Như thế này có được không thầy
Mã:
Function MyMaxIf(ByVal rngTest As Range, _
                 ByVal TestValue As Variant, _
                 ByVal rngValue As Range) As Double
    Dim i As Long
    Dim lCountCells As Long
        MyMaxIf = -2147483648#
        lCountCells = rngTest.Cells.Count
    For i = 1 To lCountCells
        If rngTest(i).Value = TestValue Then
            If MyMaxIf < rngValue(i).Value Then
                MyMaxIf = rngValue(i).Value
            End If
        End If
Next i
End Function
 
Lần chỉnh sửa cuối:
Như thế này có được không thầy
Mã:
Function MyMaxIf(ByVal rngTest As Range, _
                 ByVal TestValue As Variant, _
                 ByVal rngValue As Range) As Double
    Dim i As Long
    Dim lCountCells As Long
        MyMaxIf = -2147483648#
        lCountCells = rngTest.Cells.Count
    For i = 1 To lCountCells
        If rngTest(i).Value = TestValue Then
            If MyMaxIf < rngValue(i).Value Then
                MyMaxIf = rngValue(i).Value
            End If
        End If
Next i
End Function
Rất tốt!
Hàm đã chạy được trên vùng dữ liệu 1 cột nhiều dòng và cả vùng 1 dòng nhiều cột!
Thử nghĩ xem hàm của bạn có thể hoạt động trên vùng nhiều dòng nhiều cột hay không?
Cấu trúc dữ liệu kiểu thế này đây:

untitled.JPG

Ẹc... Ẹc... Cố lên!
 
Lần chỉnh sửa cuối:
Em thử rồi và thấy chạy ngon thầy ạ:D
 

File đính kèm

Lần chỉnh sửa cuối:
Em thử rồi và thấy chạy ngon thầy ạ:D
Ẹc... Ẹc... Đây là món tuyệt chiêu của thuộc tính Range so với Array
Ví dụ:
PHP:
Sub Test()
  Dim Rng As Range
  Set Rng = Range("A1:B10")
  MsgBox Rng(12)
End Sub
Rng(12) sẽ là = giá trị của cell B6, tức nằm tại dòng 6 cột 2 của vùng Rng
Và đây cũng là cái dở của Range so với Array ---> Vì nhìn vào số 12, ta chẳng tài nào đoán được đấy là vị trí nào
Mai này, khi bạn giỏi về VBA 1 chút, bạn sẽ thấy rằng để tăng tốc độ tính toán cho code VBA, không gì bằng đưa mọi thứ về mảng, và việc truy xuất mảng tuy là gần giống với truy xuất Range nhưng cũng sẽ có chổ khác biệt ----> Ví dụ với code trên nếu biến Rng là Array thì câu lệnh MsgBox Rng(12) báo lỗi ngay lập tức
 
Sơ suất quá, em sửa lại ạ

Mình sửa lại chút code của Hưng cho hàm MinIf:
PHP:
Public Function MyMinIf(ByVal rngTest As Range, _
                 ByVal TestValue As Variant, _
                 ByVal rngValue As Range) As Double
    Dim i As Long
    Dim lCountCells As Long
        MyMinIf = 2147483648#
        lCountCells = rngTest.Cells.Count
    For i = 1 To lCountCells
        If rngTest(i).Value = TestValue Then
            If MyMinIf > rngValue(i).Value Then
                MyMinIf = rngValue(i).Value
            End If
        End If
    Next
End Function
 
Mình sửa lại chút code của Hưng cho hàm MinIf:
PHP:
Public Function MyMinIf(ByVal rngTest As Range, _
                 ByVal TestValue As Variant, _
                 ByVal rngValue As Range) As Double
    Dim i As Long
    Dim lCountCells As Long
        MyMinIf = 2147483648#
        lCountCells = rngTest.Cells.Count
    For i = 1 To lCountCells
        If rngTest(i).Value = TestValue Then
            If MyMinIf > rngValue(i).Value Then
                MyMinIf = rngValue(i).Value
            End If
        End If
    Next
End Function
Các bạn lưu ý rằng, trong Excel, số lớn nhất và nhỏ nhất mà nó có thể hiểu được không phải là 2147483648-2147483648 đâu nha, nó chính là số 9.99999999999999E+307-9.99999999999999E+307
Hãy thử hàm của bạn với dữ liệu thế này sẽ thấy kết quả trật lất:

untitled.JPG

Hãy xem bài #140 ---> Nó cho kết quả đúng trong trường hợp này đấy
 
Lần chỉnh sửa cuối:
Các bạn lưu ý rằng, trong Excel, số lớn nhất và nhỏ nhất mà nó có thể hiểu được không phải là 2147483648-2147483648 đâu nha, nó chính là số 9.99999999999999E+307-9.99999999999999E+307
Hãy thử hàm của bạn với dữ liệu thế này sẽ thấy kết quả trật lất:

View attachment 54492

Hãy xem bài #140 ---> Nó cho kết quả đúng trong trường hợp này đấy
NDU làm giúp 1 UDF = array. Mình đang phân vân rngTest là nhiều dòng nhiều cột thì nên dùng mảng 1 hay 2 chiều nào cho tối ưu. Cám ơn.
 
NDU làm giúp 1 UDF = array. Mình đang phân vân rngTest là nhiều dòng nhiều cột thì nên dùng mảng 1 hay 2 chiều nào cho tối ưu. Cám ơn.
Bài #140 là Array rồi đấy ThuNghi ơi ---> Tôi đang dùng mảng 2 chiều
Còn 1 chuyện nữa có thể suy nghĩ nữa (trong tương lai), đó là cải tiến đề hàm làm việc được với 1 vùng dữ liệu tùy ý, tức có thể nhiều dòng nhiều cột, thậm chí là vùng không liên tục
 
If ResRng(i, 1) > TmpMax Then TmpMax = ResRng(i, j).Value
Em không hiểu dòng này lắm, tại sao lại là ResRng(i,1) hả bác. Theo em phải là
If ResRng(i, j).Value> TmpMax Then TmpMax = ResRng(i, j).Value
 
If ResRng(i, 1) > TmpMax Then TmpMax = ResRng(i, j).Value
Em không hiểu dòng này lắm, tại sao lại là ResRng(i,1) hả bác. Theo em phải là
If ResRng(i, j).Value> TmpMax Then TmpMax = ResRng(i, j).Value
Code của anh NDU bị nhầm đấy Bạn. Đúng ra phải như vầy:
Mã:
[COLOR=#000000][COLOR=#007700]If [/COLOR][/COLOR][COLOR=#000000][COLOR=#0000bb]ResRng[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]i[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]j[/COLOR][COLOR=#007700]).[/COLOR][COLOR=#0000bb]Value[/COLOR][/COLOR][COLOR=#000000][COLOR=#007700]> [/COLOR][COLOR=#0000bb]TmpMax Then TmpMax [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]ResRng[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]i[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]j[/COLOR][COLOR=#007700]).[/COLOR][COLOR=#0000bb]Value
[/COLOR][/COLOR]
 
Hoá ra em phát hiện đúng khà khà
 
Em muốn hỏi nếu làm hàm MySumIf hay MyCountIf mà điều kiện không phải là một giá trị mà là một khoảng, như tìm tổng của tất cả những số trong vùng có giá trị lớn hơn (hay nhỏ hơn) một số cụ thể thì làm thế nào?
Ví dụ như hàm sẵn có trong excel thì ta có thể viết =SumIf(A1:B5,">10")
 
Em muốn hỏi nếu làm hàm MySumIf hay MyCountIf mà điều kiện không phải là một giá trị mà là một khoảng, như tìm tổng của tất cả những số trong vùng có giá trị lớn hơn (hay nhỏ hơn) một số cụ thể thì làm thế nào?
Ví dụ như hàm sẵn có trong excel thì ta có thể viết =SumIf(A1:B5,">10")

Nếu bạn chưa trãi qua cấu trúc For Each. . . . Next, thì ta lập ra 2 vòng lặp cho 2 cột dữ liệu đó

Sau đó, trong quá trình duyệt 2 vòng lặp, cái nào ưng í thì ta cộng thêm vô MySumIf của bạn

Hứa hẹn 1 thành công mĩ mãn với buổi sáng tốt lành!
 
Nếu bạn chưa trãi qua cấu trúc For Each. . . . Next, thì ta lập ra 2 vòng lặp cho 2 cột dữ liệu đó

Sau đó, trong quá trình duyệt 2 vòng lặp, cái nào ưng í thì ta cộng thêm vô MySumIf của bạn

Hứa hẹn 1 thành công mĩ mãn với buổi sáng tốt lành!

Trong trường hợp tổng quát thì tham số thứ 2 sẽ được người dùng gõ vào, thí dụ ">10", ">=20", "<>100", "<10^5", ...
Không đơn giản dối với trình độ của lớp hiện giờ đâu, kể cả tầm trung bình. (Select Case, InStr tách chuỗi, Replace và Val chẳng hạn)
 
Lần chỉnh sửa cuối:
Nếu 1 tham số fức tạp thì ta tách ra làm 2 cái đơn giản, như đang dởn vậy mà

Các bạn trong lớp thử xem sao nha:

MySumIf (Rng2Cot As Range, dNum As Double, sType As String)

Ta quy ước với hàm fải hiểu các tham số nhập vô như sau:

sType | Fải hiểu
"B"| "="
"NB"|"<="
"LB"|">="
"L"|">"
"N"|"<"


Khà, khà, . . . . . vụng chèo khéo chống í mà!
 
Lần chỉnh sửa cuối:
Các bạn trong lớp thử xem sao nha:

MySumIf (Rng2Cot As Range, dNum As Double, sType As String)

Ta quy ước với hàm fải hiểu các tham số nhập vô như sau:

sType | Fải hiểu
"B"| "="
"NB"|"<="
"LB"|">="
"L"|">"
"N"|"<"

Khà, khà, . . . . . vụng chèo khéo chống í mà!
Em làm theo ý bác ạ


PHP:
Function MySumIf(ByVal rngValue As Range, ByVal lTest As Long, ByVal sType As String) As Long
    Dim i As Long, j As Long
    For i = 1 To rngValue.Rows.Count
        For j = 1 To rngValue.Columns.Count
            Select Case sType
                Case "k","K"
                    If rngValue(i, j) <> lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "B", "b"
                    If rngValue(i, j) = lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "NB", "Nb", "nb", "nB"
                    If rngValue(i, j) <= lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "NH", "Nh", "nh", "nH"
                    If rngValue(i, j) < lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "LB", "Lb", "lb", "lB"
                    If rngValue(i, j) >= lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "LH", "Lh", "lh", "lH"
                    If rngValue(i, j) > lTest Then MySumIf = MySumIf + rngValue(i, j)
            End Select
        Next
    Next
End Function
 

File đính kèm

Lần chỉnh sửa cuối:
Các bạn trong lớp thử xem sao nha:

MySumIf (Rng2Cot As Range, dNum As Double, sType As String)

Ta quy ước với hàm fải hiểu các tham số nhập vô như sau:

sType | Fải hiểu
"B"| "="
"NB"|"<="
"LB"|">="
"L"|">"
"N"|"<"


Khà, khà, . . . . . vụng chèo khéo chống í mà!
Chả hiểu hàm countif(....,">=100") trong excel nó dịch phần ">=100" ra làm sao.
Nếu dùng replace hay instr thì có vẻ rừng quá. Mà dùng "L" hay "LB" em thấy còn rừng hơn. Hay dùng Cvar(...) chả biết có OK.
Các bác giúp em giải thuật tách ">=100" ra.
Cám ơn các bác.
Em dùng thử code sau để test không biết có đúng không. Các bác xem giúp em.
PHP:
Function Kiemtra(Rng As Range, sStr As String) As Boolean
  Kiemtra = Evaluate(Rng & sStr)
End Function
Cú pháp
=KiemTra(A1,">=1000")
Nếu A1 >= 1000 thì true.
 
Lần chỉnh sửa cuối:
Thay vì Case "NB", "Nb", "nb", "nB" ta có thể dùng Select Case Ucase(sType) chứ nhỉ?

Bác Sa chắc lụt nghề, hoặc là đang thử anh em. Dùng B, LB, L, NB, N, còn thiếu 1 ký hiệu K = "<>". Mà đã tách ta 2 tham số thì để nguyên >, <, >=, <=, <> cho khoẻ. Select Case khỏi B, b, khỏi NB, nb, Nb, nB, lung tung xà bần. Dùng Evaluate như ThuNghi có thể không cần tách ra 2 tham số.
 
Thay vì Case "NB", "Nb", "nb", "nB" ta có thể dùng Select Case Ucase(sType) chứ nhỉ?

Bác Sa chắc lụt nghề, hoặc là đang thử anh em. Dùng B, LB, L, NB, N, còn thiếu 1 ký hiệu K = "<>". Mà đã tách ta 2 tham số thì để nguyên >, <, >=, <=, <> cho khoẻ. Select Case khỏi B, b, khỏi NB, nb, Nb, nB, lung tung xà bần. Dùng Evaluate như ThuNghi có thể không cần tách ra 2 tham số.

Các bác làm em loạn hết cả rồi, bài trên em làm là tất cả kiến thức bọn em mới học, còn kiến thức khác thì bọn em chịu không biết gì luôn.
 
Tôi nói trong trình độ của lớp ấy chứ. Thí dụ sau không cần xét mọi trường hợp như nb, NB, Nb, nB, dùng nguyên code của hungtttv, có bổ sung ký hiệu K = <>:
PHP:
Function MySumIf(ByVal rngValue As Range, ByVal lTest As Long, ByVal sType As String) As Long
    Dim i As Long, j As Long
    For i = 1 To rngValue.Rows.Count
        For j = 1 To rngValue.Columns.Count
            Select Case UCase(sType)
                Case "B"
                    If rngValue(i, j) = lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "NB"
                    If rngValue(i, j) <= lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "NH"
                    If rngValue(i, j) < lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "LB"
                    If rngValue(i, j) >= lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "LH"
                    If rngValue(i, j) > lTest Then MySumIf = MySumIf + rngValue(i, j)
                Case "K"
                    If rngValue(i, j) <> lTest Then MySumIf = MySumIf + rngValue(i, j)
            End Select
        Next
    Next
End Function

Còn nếu để nguyên các ký hiệu như cũ, sẽ dễ dành cho người dùng hơn, (nguyên tắc viết code là viết hàm thuận tiện cho người dùng, chứ không phải viết hàm thuận tiện cho người viết).

PHP:
Function MySumIf(ByVal rngValue As Range, ByVal lTest As Long, ByVal sType As String) As Long
    Dim i As Long, j As Long
    For i = 1 To rngValue.Rows.Count
        For j = 1 To rngValue.Columns.Count
            Select Case sType
                Case "="

                Case "<="
 
                Case "<"

                Case ">="

                Case ">"

                Case "<>"
            End Select
        Next
    Next
End Function
 
Các thầy có bài nào phù hợp với những kiến thức bọn em đã học thì các thầy đưa lên đây để bọn em làm nhé. Em nghĩ trong các kiến thức bọn em học trên lớp đã có rất nhiều vấn đề mà bọn em chưa va phải, mà chỉ có cách là làm bài tập nhiều mới thấy được thôi. EM cám ơn trước ạ!!!
 
Ủa sao kỳ vậy ta! SUMIF mà sao chỉ có Vùng điều kiện, còn vùng tính tổng ở đâu?
Lý ra thì hàm này phải có 3 tham số ---> MySumIf(SourceRange as Range, Criteria, SumRange as Range)
Nếu bỏ qua SumRange thì sẽ gán SumRange = SourceRange
---------------
Nghiên cứu cũng để chơi thôi chứ muốn bắt chước y chang như SUMIF của bác Bill thật chẳng dễ nhai đâu!
 
Ủa sao kỳ vậy ta! SUMIF mà sao chỉ có Vùng điều kiện, còn vùng tính tổng ở đâu?
Lý ra thì hàm này phải có 3 tham số ---> MySumIf(SourceRange as Range, Criteria, SumRange as Range)
Nếu bỏ qua SumRange thì sẽ gán SumRange = SourceRange
---------------
Nghiên cứu cũng để chơi thôi chứ muốn bắt chước y chang như SUMIF của bác Bill thật chẳng dễ nhai đâu!

Em thấy SumRange không có cũng được mà bác. Trong hàm Sumif không có cũng được mà
Đây là làm theo yêu cầu của Khanhhoan thôi

Em muốn hỏi nếu làm hàm MySumIf hay MyCountIf mà điều kiện không phải là một giá trị mà là một khoảng, như tìm tổng của tất cả những số trong vùng có giá trị lớn hơn (hay nhỏ hơn) một số cụ thể thì làm thế nào?
Ví dụ như hàm sẵn có trong excel thì ta có thể viết =SumIf(A1:B5,">10")
 
Em thấy SumRange không có cũng được mà bác. Trong hàm Sumif không có cũng được mà
Đây là làm theo yêu cầu của Khanhhoan thôi
Không có cũng được có nghĩa là khi dùng bạn có thể bỏ qua tùy theo yêu cầu... Còn khi viết hàm thì phải đủ chứ ---> Có phải lúc nào vùng tính tồng và vùng điều kiện cũng là một đâu nè
-------------
Vẫn còn chưa nói đến cái vụ KÝ TỰ ĐẠI DIỆN * ? nữa đấy nha
 
Lần chỉnh sửa cuối:
Các thầy có bài nào phù hợp với những kiến thức bọn em đã học thì các thầy đưa lên đây để bọn em làm nhé. Em nghĩ trong các kiến thức bọn em học trên lớp đã có rất nhiều vấn đề mà bọn em chưa va phải, mà chỉ có cách là làm bài tập nhiều mới thấy được thôi. EM cám ơn trước ạ!!!
Có bài này là lấy trên GPE từ TransferData của NDU đã làm, các bạn viết cho 1 hàm Max và Min Price theo 2 điều kiện là Company Name và Services. Tuỳ chọn tại F2 và G2 của file.
Tôi mới làm ct mà ct mảng nên chậm quá, các bạn giúp tôi làm 1 UDF nhé.
Hy vọng bài loại này có nhiều áp dụng thực tế.
Cám ơn các bạn nhiều.
 

File đính kèm

Không có cũng được có nghĩa là khi dùng bạn có thể bỏ qua tùy theo yêu cầu... Còn khi viết hàm thì phải đủ chứ ---> Có phải lúc nào vùng tính tồng và vùng điều kiện cũng là một đâu nè
Em chỉ lấy ví dụ đơn giản như cho 1 vùng số và tính tổng của tất cả những số trong vùng mà lớn hơn 1 giá trị a nào đó, hàm sumif của excel cũng làm được điều này mà chỉ cần vùng chứa số liệu và điều kiện ">a". Chỉ là chức năng giống nhau thôi chứ em không nói là viết 1 hàm giống hệt SUMIF.
 
Lần chỉnh sửa cuối:
Tôi mới làm ct mà ct mảng nên chậm quá, các bạn giúp tôi làm 1 UDF nhé.
Hy vọng bài loại này có nhiều áp dụng thực tế.
Cám ơn các bạn nhiều.
Chẳng lý nào với bài này mà ThuNghi lại NHỜ GIÚP ---> Chắc đưa bài lên cho các bạn khác làm bài tập đây?
------------------------
Em chỉ lấy ví dụ đơn giản như cho 1 vùng số và tính tổng của tất cả những số trong vùng mà lớn hơn 1 giá trị a nào đó, hàm sumif của excel cũng làm được điều này mà chỉ cần vùng chứa số liệu và điều kiện ">a". Chỉ là chức năng giống nhau thôi chứ em không nói là viết 1 hàm giống hệt SUMIF.
Đồng ý rằng ta "hạ độ khó" của bài toán cho các bạn dễ nghiên cứu, tìm hiểu... Nhưng nếu muốn tiến bộ, hãy nghĩ đến hướng "nâng cao" NGAY TỪ BÂY GIỜ đi
 
Xin phép các bác cho em khởi động bài tập về nhà ngày hôm qua. Thầy cho 2 bài, đây là bài 1:
Đề bài: Viết thủ tục tìm dòng cuối cùng của 1 vùng nào đó
Đây là bài làm của em (Mặc dù em biết có cách sử dụng .End(xlUp) cũng có thể xác định được dòng cuối cùng, nhưng em đang làm theo nhưng vòng lặp đã học (Do While, For) để xác định, có thể bài hơi dài, mong các bác góp ý.

Mã:
Sub LastCell()
    Dim rngNum As Range
    Dim i As Integer
    Dim j As Integer
    Dim x As Integer
        
    Set rngNum = Selection
    i = rngNum.Rows.Count
    x = 1
    Do While i <> 0
    For j = 1 To rngNum.Columns.Count
        If IsEmpty(rngNum.Cells(i, j)) = False Then
        userrespond = MsgBox("Dong cuoi cung la " & rngNum.Cells(i, j).Row, vbOKOnly, "Thong bao!")
        x = 0
        Exit Do
        End If
    Next
    i = i - 1
    Loop
    If x = 1 Then
    userrespond = MsgBox("Vung du lieu toan dong trang", vbOKOnly, "Thong bao!")
    End If
End Sub

P/S: Bác Ngọc NH_DK có thể gửi PM kho vào hòm thư thangacc@gmail.com cho em nhé, có gì anh em cùng trao đổi. Cảm ơn bác
 
Lần chỉnh sửa cuối:
Đây là code BT1 nhé:
PHP:
Sub Tim_dong()
    Dim rngVung As Range, i As Long
    i = 1
        Do While i <= Range("A1:A65535").Count
            If Not IsEmpty(Range("A1:A65535").Item(i)) _
            Then Set rngVung = Range("A1:A65535").Item(i)
         i = i + 1
    Loop
    If rngVung Is Nothing Then
        MsgBox "Khong thay dong DL nao ca!"
    Else
        MsgBox "Dong DL cuoi cung la: " & rngVung.Address
    End If
    Set rngVung = Nothing
End Sub
 
Lần chỉnh sửa cuối:
Xin phép các bác cho em khởi động bài tập về nhà ngày hôm qua. Thầy cho 2 bài, đây là bài 1:
Đề bài: Viết thủ tục tìm dòng cuối cùng của 1 vùng nào đó
Đây là bài làm của em (Mặc dù em biết có cách sử dụng .End(xlUp) cũng có thể xác định được dòng cuối cùng, nhưng em đang làm theo nhưng vòng lặp đã học (Do While, For) để xác định, có thể bài hơi dài, mong các bác góp ý.

Mã:
Sub LastCell()
    Dim rngNum As Range
    Dim i As Integer
    Dim j As Integer
    Dim x As Integer
        
    Set rngNum = Selection
    i = rngNum.Rows.Count
    x = 1
    Do While i <> 0
    For j = 1 To rngNum.Columns.Count
        If IsEmpty(rngNum.Cells(i, j)) = False Then
        userrespond = MsgBox("Dong cuoi cung la " & rngNum.Cells(i, j).Row, vbOKOnly, "Thong bao!")
        x = 0
        Exit Do
        End If
    Next
    i = i - 1
    Loop
    If x = 1 Then
    userrespond = MsgBox("Vung du lieu toan dong trang", vbOKOnly, "Thong bao!")
    End If
End Sub
P/S: Bác Ngọc NH_DK có thể gửi PM kho vào hòm thư thangacc@gmail.com cho em nhé, có gì anh em cùng trao đổi. Cảm ơn bác
Đã gọi là CÓ DỮ LIỆU thì phải tính luôn Comment nữa nha
Ngoài ra, nếu dùng vòng lập, nên quét từ dưới lên, theo nguyên tắc:
- Cho trước biến MaxRow = 0
- Quét từng cột
- Quét từng dòng, từ dưới lên, nếu Cell không rổng hoặc có Comment thì xét tiếp:
* Nếu MaxRow < Vị trí dòng đang xét thì gán MaxRow = Vị trí dòng ấy
- Thoát vòng lập, chuyển sang cột khác
--------
Ví dụ là thế này:
PHP:
Sub xLastCell()
  Dim sRng As Range, i As Long, j As Long, MaxR As Long, Answer As String
  Set sRng = Selection
  For j = 1 To sRng.Columns.Count
    For i = sRng.Rows.Count To 1 Step -1
      If Not IsEmpty(sRng(i, j)) Or Not sRng(i, j).Comment Is Nothing Then
        If MaxR < sRng(i, j).Row Then MaxR = sRng(i, j).Row
        Exit For
      End If
    Next
  Next
  Answer = IIf(MaxR, "Dong cuoi cùng la " & MaxR, "Vùng du liêu toàn dòng trang")
  MsgBox Answer, 6, "Thông báo"
End Sub
 
Lần chỉnh sửa cuối:
Em sửa lại chút xíu cho rộng hơn nè............
PHP:
Sub Tim_dong()
    Dim rngVung As Range, i As Long
    i = 1
        Do While i <= Selection.Count
            If Not IsEmpty(Selection.Item(i)) _
            Then Set rngVung = Selection.Item(i)
         i = i + 1
    Loop
    If rngVung Is Nothing Then
        MsgBox "Khong thay dong DL nao ca!"
    Else
        MsgBox "Dong DL cuoi cung la: " & rngVung.Address
    End If
    Set rngVung = Nothing
End Sub
 
Cảm ơn thầy, em không để ý tới ô chứ comment trong vùng. Code của thầy rõ ràng và ngắn gọn hơn hẳn.
Thực ra vòng Do While của em cũng xét từ dưới lên trên, và khi đã xét từ dưới lên trên thì khi nào có dữ liệu thì dòng đó sẽ là dòng cuối (max), theo em nghĩ không cần thiết phải gán thêm 1 biến MaxRow vào, có thể xác định luôn nó
Ý em là dòng
If MaxR < sRng(i, j).Row Then MaxR = sRng(i, j).Row
có thể sửa thành
Và theo em sau khi đã có giá trị MaxR, ca 2 vòng lặp không cần chạy nữa, vì vậy nên tách ra Do ... While bên ngoài vong For để mình dùng Exit Do, nó sẽ thoát luôn. Nếu không sau khi Exit For vòng lặp vẫn chạy thêm các giá trị của j còn lại --> sẽ bị lâu
 
Cảm ơn thầy, em không để ý tới ô chứ comment trong vùng. Code của thầy rõ ràng và ngắn gọn hơn hẳn.
Thực ra vòng Do While của em cũng xét từ dưới lên trên, và khi đã xét từ dưới lên trên thì khi nào có dữ liệu thì dòng đó sẽ là dòng cuối (max), theo em nghĩ không cần thiết phải gán thêm 1 biến MaxRow vào, có thể xác định luôn nó
Ý em là dòng có thể sửa thành Và theo em sau khi đã có giá trị MaxR, ca 2 vòng lặp không cần chạy nữa, vì vậy nên tách ra Do ... While bên ngoài vong For để mình dùng Exit Do, nó sẽ thoát luôn. Nếu không sau khi Exit For vòng lặp vẫn chạy thêm các giá trị của i còn lại --> sẽ bị lâu
Đâu có được ---> Selection của ta là nhiều dòng nhiều cột! MaxRow của cột này chắc gì đã là MaxRow của cột khác
Nếu bạn thay If MaxR < sRng(i, j).Row Then MaxR = sRng(i, j).Row thành MaxR = sRng(i, j).Row thì nó sẽ lấy MaxRow ở cột cuối cùng (dù dòng cuối của cột này chưa chắc có giá trị lớn nhất)
Không tin bạn có thể thí nghiệm để kiểm chứng điều này vào code của tôi
--------------------------------
Còn cách của bạn có hơi khác... vì bạn quét theo cột trước, từ cột 1 của dòng cuối đến cột cuối của dòng cuối rồi từ đó đi lên, nếu thấy cell <> rổng thì Exit Do
Tôi thì quét theo dòng trước, từ dòng cuối cột 1 trờ lên, xong mới chuyển qua cột khác
Xét về tốc độ có lẽ bạn đã đúng ---> Vậy cứ chuyển đổi 2 vòng lập for này cho nhau là được rồi (Do hay For gì cũng được cả)
 
Lần chỉnh sửa cuối:
Vâng đúng ạ, em test bỏ if đi thì có vùng đúng, có vùng nó chọn sai dòng
 
Vâng đúng ạ, em test bỏ if đi thì có vùng đúng, có vùng nó chọn sai dòng
Trong code của tôi, nếu muốn bỏ IF thì phải đổi cấu trúc vòng lập, quét dòng trước cột sau
PHP:
Sub xLastCell()
  Dim sRng As Range, i As Long, j As Long, MaxR As Long, Answer As String
  Set sRng = Selection
  For i = sRng.Rows.Count To 1 Step -1
    For j = 1 To sRng.Columns.Count
      If Not IsEmpty(sRng(i, j)) Or Not sRng(i, j).Comment Is Nothing Then MaxR = sRng(i, j).Row
    Next
    If MaxR Then Exit For
  Next
  Answer = IIf(MaxR, "Dong cuoi cùng la " & MaxR, "Vùng du liêu toàn dòng trang")
  MsgBox Answer, 6, "Thông báo"
End Sub
 
Đã gọi là CÓ DỮ LIỆU thì phải tính luôn Comment nữa nha
Ngoài ra, nếu dùng vòng lập, nên quét từ dưới lên, theo nguyên tắc:
- Cho trước biến MaxRow = 0
- Quét từng cột
- Quét từng dòng, từ dưới lên, nếu Cell không rổng hoặc có Comment thì xét tiếp:
* Nếu MaxRow < Vị trí dòng đang xét thì gán MaxRow = Vị trí dòng ấy
- Thoát vòng lập, chuyển sang cột khác
Em chưa hiểu
Mã:
Comment Is Nothing Then
để làm gì, trên lớp thầy chưa dạy về lệnh này, mong các AC chỉ giúp
 
Em chưa hiểu
Mã:
Comment Is Nothing Then
để làm gì, trên lớp thầy chưa dạy về lệnh này, mong các AC chỉ giúp
Range(...).Comment Is Nothing nghĩa là Range(...) này không có Comment (Nothing mà lị)
Not Range(...).Comment Is Nothing thì có nghĩa ngược lại, Range(...) có Comment
Phát biểu gần như ta nói (hiểu tiếng Anh là hiểu ý nghĩa của lệnh)
 
Đây là BT2: Xoá ô
PHP:
Sub Xoa_O()
    Dim Vung As Range
    Dim MyCell As Range
    Set Vung = Selection
    Application.ScreenUpdating = False
    For Each MyCell In Vung
        If MyCell.Value = Empty Then
            MyCell.Delete Shift:=xlUp
        End If
    Next
    Application.ScreenUpdating = True
    Set Vung = Nothing
End Sub
Code này em mới làm được xoá 1 ô trống trong vùng thôi. Em muốn xoá 2 hay nhiều ô trống gần nhau thì vẫn chưa Ok ah. Mong thầy và các AC chỉ dùm thêm nha!!!
 

File đính kèm

Lần chỉnh sửa cuối:
Đây là BT2: Xoá ô
PHP:
Sub Xoa_O()
    Dim Vung As Range
    Dim MyCell As Range
    Set Vung = Selection
    Application.ScreenUpdating = False
    For Each MyCell In Vung
        If MyCell.Value = Empty Then
            MyCell.Delete Shift:=xlUp
        End If
    Next
    Application.ScreenUpdating = True
    Set Vung = Nothing
End Sub
Code này em mới làm được xoá 1 ô trống trong vùng thôi. Em muốn xoá 2 hay nhiều ô trống gần nhau thì vẫn chưa Ok ah. Mong thầy và các AC chỉ dùm thêm nha!!!
Mấy vụ xóa cell này phải quét từ dưới lên đồng chí ơi! Kiểu vầy:
PHP:
Sub Xoa_O()
  Dim sRng As Range, i As Long, j As Long
  Set sRng = Selection
  Application.ScreenUpdating = False
  For j = 1 To sRng.Columns.Count
    For i = sRng.Rows.Count To 1 Step -1
      If IsEmpty(sRng(i, j)) Then sRng(i, j).Delete Shift:=xlUp
    Next
  Next
  Application.ScreenUpdating = True
End Sub
Còn nếu cố tình quét từ trên xuống hoặc dùng For Each... thì không được xóa liền, phải dùng Union thu gom những cell rổng thành 1 nhóm ---> Cuối vòng lập mới xóa 1 lượt
PHP:
Sub Test()
  Dim sRng As Range, Tmp As Range, Clls As Range
  Set sRng = Selection
  Application.ScreenUpdating = False
  For Each Clls In sRng
    If IsEmpty(Clls) Then
      If Tmp Is Nothing Then
        Set Tmp = Clls
      Else
        Set Tmp = Union(Tmp, Clls)
      End If
    End If
  Next
  If Not Tmp Is Nothing Then Tmp.Delete Shift:=xlUp
  Application.ScreenUpdating = True
End Sub
Xét về mặt tốc độ thì cách 2 sẽ nhanh hơn (dù rắc rối hơn)
 
Lần chỉnh sửa cuối:
Kho tàng ẩn chứa trong fương thức Delete đây, xem thêm thử nha

Code trên này em mới làm được xoá 1 ô trống trong vùng thôi. Em muốn xoá 2 hay nhiều ô trống liện kề nhau thì vẫn chưa Ok ah. Mong thầy và các AC chỉ dùm thêm nha!!!
Bạn dùng chuột tô chọn từ 'Delete' trong macro & bấm {F1} ta sẽ được đưa đến sự hỗ trợ đắc lực từ VBE, mà trong đó mình muốn giới thiệu dòng này để bạn quan tâm
Mã:
[SIZE=3]
[B]Delete[/B][/SIZE] [SIZE=3] method as it applies to the [B]Range[/B]  object.
[I]expression[/I][/SIZE] [SIZE=3].[B]Delete[/B][B]([I]Shift[/I])
[/B][I]expression   [/I] Required. An expression that returns a [B][URL="http://www.giaiphapexcel.com/forum/xlobjRange1.htm"]Range[/URL][/B] object.
 [B][I]1
[/I][/B]
[B][I] Shift[/I][/B][/SIZE] [SIZE=3] Optional [B]Variant[/B].  Used only with [B]Range[/B] objects. Specifies how to shift cells to  replace deleted cells. 
Can be one of the following [B]XlDeleteShiftDirection[/B] constants: [B]xlShiftToLeft[/B] or [B]xlShiftUp[/B]. 
If this argument  is omitted, Microsoft Excel decides based on the shape of the range.[/SIZE]
Nếu bạn hiểu sâu câu sau số 1 đó thì bạn sẽ biết cách khắc fục nhược điểm của macro 1 cách tạm thời.

Hay thế này đi: Giả dụ tôi & bạn, chúng ta có bảng dữ liệu sau:

| B | C 1 |GPE|
2 |5|
3 |6|
4 |7|
5 ||8
6 ||9
7 |4|
8 |3|(8 dòng)

Bạn thêm tham số này vô lệnh xóa ô trên : xlShiftToLeft

Tô chọn vùng cột 'B' bên trên & cho macro chạy; Fa li càfê để gặm nhắm những gì vừa xuất hiện trong đầu của bạn.



 
Lần chỉnh sửa cuối:
Đây là code bài xoá dòng & cột của em (chỉ dùng for next)
Mã:
Option Explicit

Sub XoaDongTrong()
Dim i As Long, j As Long, SoHang As Long, SoCot As Long, VungChon As Range
Set VungChon = Selection
SoHang = Selection.Rows.Count
SoCot = Selection.Columns.Count
    For i = 1 To SoHang
        For j = 1 To SoCot - 1
        j = j + 1
                    If VungChon(i, j).Value = Empty And VungChon(i, j + 1).Value = Empty Then
                        VungChon.Rows(i).Delete
                    End If
        Next j
    Next i
Set VungChon = Nothing
End Sub
'------------------------------------------------------------------------------------------------------
Sub XoaCotTrong()
Dim i As Long, j As Long, SoHang As Long, SoCot As Long, VungChon As Range
Set VungChon = Selection
SoHang = Selection.Rows.Count
SoCot = Selection.Columns.Count
    For j = 1 To SoCot
        For i = 1 To SoHang - 1
        i = i + 1
                    If VungChon(i, j).Value = Empty And VungChon(i + 1, j).Value = Empty Then
                        VungChon.Columns(j).Delete
                    End If
        Next i
    Next j
Set VungChon = Nothing
End Sub
Anh ChanhTQ@ hướng dẫn ở trên nhưng em chưa hiểu lắm làm thế nào để chỉ xoá 1 hàng (cột) trong phạm vi vùng chọn mà không ảnh hưởng đến các cell khác bên cạnh giống như Shift Cell Up hay Shift Cell Left trong excel.
 

File đính kèm

Lần chỉnh sửa cuối:
nhưng em chưa hiểu lắm làm thế nào để chỉ xoá 1 hàng (cột) trong phạm vi vùng chọn mà không ảnh hưởng đến các cell khác bên cạnh giống như Shift Cell Up hay Shift Cell Left trong excel.
Tựu chung vấn đề là: Khi xài fương thức Delete ta hiểu thêm nó có 2 tham số, mà 1 trong chúng đã ngầm định;

đó là xlShiftUp; Với tham số này, khi ta xóa 1 ô, thì DL (dữ liệu) ô dưới nó sẽ được đôn lên chỗ ô bị xóa, & cứ thế đôn lên cho hết cột của ô bị xóa.

Nếu ta xóa nguyên hàng có ô đó, thì DL hàng dưới liền kề sẽ được đôn lên thay chỗ cho hàng vừa bị xóa.
Điều này diễn ra thật sự trên trang tính excel, như lâu nay bạn đã thấy đó nha!

Trở lại vụ dùng vòng lặp để xóa các ô trống trong cột:

Khi [B5] trống, ta dùng fương thức Delete để xóa ô này, thì DL ô [B6] đã được đôn lên thế chỗ ngay tấp lư. ([B7] thay cho [B6],. . . ) Sau thời điểm thế chỗ xong, vòng lặp lại tiếp tục, nhưng các bạn có biết không, nó nhãy vô ô [B6], mà ô này đang chứa DL của anh chàng dưới nó trước đây;

Như vậy nếu cả 2 ô [B5] & [B6] ban đầu là rỗng, thì fương thức xóa ô trống từ đầu cột đến cuối cột sẽ để sót, một khi có 2 ô trống trong cột liền kề nhau; (Các bạn thử với 3 & 4 ô trống liền kề & tự rút ra kết luận nha!)

Cách khắc phục việc này:

Ta duyệt từ ô tận cùng của cột để dò lên cho đến đầu. (Tất nhiên nếu thầy Tuân đã hướng dẫn cách duyệt vòng lặp ngược từ cuối trở lên đầu;
Nếu chưa hướng dẫn thì các bạn sẽ không xóa được 2 ô trống liền kề trong 1 lần chạy macro;
Mà các bạn fải chạy bao nhiêu lần í, mới hết các ô trong có thể có trong 1 cột; Số lần chạy đó cũng xin nhường các bạn tính sao cho fải đạo, nhứt là các bạn đã & trãi qua fỗ thông trung học.)

Rất vui, nếu những gì viết trên đây hữu ích cho các bạn trong lớp!

Thân ái!






 
Chỉnh sửa lần cuối bởi điều hành viên:
Vì các bạn đang học vòng lập nên ta giải quyết mọi chuyện bằng vòng lập... Thật ra bài này có cách khác hay hơn rất nhiều:
PHP:
Sub Test2()
  Dim sRng As Range
  On Error Resume Next
  Set sRng = Selection
  If sRng.Count > 1 Then sRng.SpecialCells(4).Delete 2
End Sub
 
Vì các bạn đang học vòng lập nên ta giải quyết mọi chuyện bằng vòng lập... Thật ra bài này có cách khác hay hơn rất nhiều:
PHP:
Sub Test2()
  Dim sRng As Range
  On Error Resume Next
  Set sRng = Selection
  If sRng.Count > 1 Then sRng.SpecialCells(4).Delete 2
End Sub

Em hiểu được con số 4 SpecialCells(4) như vầy:

If sRng.Count > 1 Then sRng.SpecialCells(xlCellTypeBlanks).Delete 2

Bác ơi ndu cho em hỏi số 2 nghĩa là gì ạ. E có thể xem thêm giá trị kiểu gán Delete 2 này ở đâu?

Thanks Bác!
 
Lần chỉnh sửa cuối:
Em hiểu được con số 4 SpecialCells(4) như vầy:



Bác ơi ndu cho em hỏi số 2 nghĩa là gì ạ. E có thể xem thêm giá trị kiểu gán Delete 2 này ở đâu?

Thanks Bác!
Theo cách hiểu của Mình là: Bạn bấm chọn 1 ô bất kỳ -> Bấm phải chuột chọn Delete -> Nó sẽ xuất hiện hộp thoại Delete -> Xem thứ tự từ trên xuống
Delete Shist Cells Left (Tương ứng là 1)
Delete Shist Cells Up (Tương ứng là 2)
.......
 
Tôi thấy yêu cầu bài là tìm LastRow, yêu cầu này thấy thiết thực. Các Bác lại chuyển sang xóa (delete) 1 cell hay nhiều Cell, vấn đề này sẽ ảnh hưởng đéb cấu trúc cơ sở dữ liệu (CSDL). Thú thật với CSDL nói chung thì việc xóa 1 cell là không nên.
Xóa nguyên dòng hay nguyên cột thì OK hay chỉ dừng lại ở Clear...
Các Bạn làm giúp mình hàm MinMaxIf mình nhờ có vẻ thực tế hơn.
Bác NDU và Bác Sa khoan đưa các bạn ấy vào vòng luẩn quẩn.
 
Em hiểu được con số 4 SpecialCells(4) như vầy:. . .
Bác ơi ndu cho em hỏi số 2 nghĩa là gì ạ. E có thể xem thêm giá trị kiểu gán Delete 2 này ở đâu?

Đó là cách viết không được tường minh cho lắm; Mình biết chắc rằng thầy Tuân đang yêu cầu các bạn viết theo kiểu tường minh
Vậy các bạn chỉ tham khảo lúc rỗi thôi, vậy nha. . . !

To ThuNghi

Delete Cells là bài tập thứ 2 của chương trình mà,. . .
 
Mã:
[Xin phép các bác cho em khởi động bài tập về nhà ngày hôm qua. Thầy cho 2 bài, đây là bài 1:
Đề bài: Viết thủ tục tìm dòng cuối cùng của 1 vùng nào đó
Đây là bài làm của em (Mặc dù em biết có cách sử dụng .End(xlUp) cũng có thể xác định được dòng cuối cùng, nhưng em đang làm theo nhưng vòng lặp đã học (Do While, For) để xác định, có thể bài hơi dài, mong các bác góp ý.

Code:
Sub LastCell()
    Dim rngNum As Range
    Dim i As Integer
    Dim j As Integer
    Dim x As Integer
        
    Set rngNum = Selection
    i = rngNum.Rows.Count
    x = 1
    Do While i <> 0
    For j = 1 To rngNum.Columns.Count
        If IsEmpty(rngNum.Cells(i, j)) = False Then
        userrespond = MsgBox("Dong cuoi cung la " & rngNum.Cells(i, j).Row, vbOKOnly, "Thong bao!")
        x = 0
        Exit Do
        End If
    Next
    i = i - 1
    Loop
    If x = 1 Then
    userrespond = MsgBox("Vung du lieu toan dong trang", vbOKOnly, "Thong bao!")
    End If
End Sub
P/S: Bác Ngọc NH_DK có thể gửi PM kho vào hòm thư email [email]thangacc@gmail.com[/email] .email cho em nhé, có gì anh em cùng trao đổi. Cảm ơn bác
thay đổi nội dung bởi: ThangAcc, 05-11-10 lúc 09:33 AM]

[/em nghĩ hình như mọi người đang hiểu nhầm ý thầy Tuân muốn chúng ta làm bài tập này. em cho chạy thử code anh Thắng post lên (và 1 số người nữa) thì thấy rằng khi chạy em phải chọn vùng dữ liệu cần tìm dòng cuối cùng hoặc là chỉ vào dòng cuối cùng của vùng đó. nếu thế thì cần gì phải làm code đi tìm dòng cuối làm gì nữa chứ vì khi em chọn vùng dữ liệu là em đã biết dòng cuối là dòng nào rồi đúng ko.
theo em thì ý của thầy là khi mình đặt con chỏ vào đâu thì nó cũng sẽ thông báo msgbox dòng cuối cùng là dòng nào và tự động chạy đến đấy luôn chứ ko cần phải chọn vùng dữ liệu.]
 
Lần chỉnh sửa cuối:
Mã:
[Xin phép các bác cho em khởi động bài tập về nhà ngày hôm qua. Thầy cho 2 bài, đây là bài 1:
Đề bài: Viết thủ tục tìm dòng cuối cùng của 1 vùng nào đó
Đây là bài làm của em (Mặc dù em biết có cách sử dụng .End(xlUp) cũng có thể xác định được dòng cuối cùng, nhưng em đang làm theo nhưng vòng lặp đã học (Do While, For) để xác định, có thể bài hơi dài, mong các bác góp ý.

Code:
Sub LastCell()
    Dim rngNum As Range
    Dim i As Integer
    Dim j As Integer
    Dim x As Integer
        
    Set rngNum = Selection
    i = rngNum.Rows.Count
    x = 1
    Do While i <> 0
    For j = 1 To rngNum.Columns.Count
        If IsEmpty(rngNum.Cells(i, j)) = False Then
        userrespond = MsgBox("Dong cuoi cung la " & rngNum.Cells(i, j).Row, vbOKOnly, "Thong bao!")
        x = 0
        Exit Do
        End If
    Next
    i = i - 1
    Loop
    If x = 1 Then
    userrespond = MsgBox("Vung du lieu toan dong trang", vbOKOnly, "Thong bao!")
    End If
End Sub
P/S: Bác Ngọc NH_DK có thể gửi PM kho vào hòm thư email [email]thangacc@gmail.com[/email] .email cho em nhé, có gì anh em cùng trao đổi. Cảm ơn bác
thay đổi nội dung bởi: ThangAcc, 05-11-10 lúc 09:33 AM]

[/em nghĩ hình như mọi người đang hiểu nhầm ý thầy Tuân muốn chúng ta làm bài tập này. em cho chạy thử code anh Thắng post lên (và 1 số người nữa) thì thấy rằng khi chạy em phải chọn vùng dữ liệu cần tìm dòng cuối cùng hoặc là chỉ vào dòng cuối cùng của vùng đó. nếu thế thì cần gì phải làm code đi tìm dòng cuối làm gì nữa chứ vì khi em chọn vùng dữ liệu là em đã biết dòng cuối là dòng nào rồi đúng ko.
theo em thì ý của thầy là khi mình đặt con chỏ vào đâu thì nó cũng sẽ thông báo msgbox dòng cuối cùng là dòng nào và tự động chạy đến đấy luôn chứ ko cần phải chọn vùng dữ liệu.]

He..he...Anh đã bảo rùi mà tuỳ từng trường hợp. Bài của Thangacc và mọi người anh nghĩ là ko sai chút nào. Đúng hoà toàn luôn.

em cho chạy thử code anh Thắng post lên (và 1 số người nữa) thì thấy rằng khi chạy em phải chọn vùng dữ liệu cần tìm dòng (*)cuối cùng hoặc là chỉ vào dòng (*) cuối cùng của vùng đó. nếu thế thì cần gì phải làm code đi tìm dòng cuối làm gì nữa chứ vì khi em chọn vùng dữ liệu là em đã biết dòng cuối là dòng nào rồi đúng ko.

- Cái quan trọng nhất thì em bỏ qua trong dấu (*) phải là: "chứa dữ liệu". Viết lại dòng màu đỏ là: Tìm dòng chứa dữ liệu cuối cùng trong vùng được chọn. Em có biết hàm Row trong Excel không? Nhìn là biết dòng nào rùi mà. Sao phải bày đặt hàm ROW() làm gì? Trả lời được câu này, từ đó huongchuoi suy ra được cái mọi người đang làm là đúng.

- Hơn nữa trong phạm vi kiến thức mình được học và làm được đúng cái mình muốn là được.

- Còn thực tiển cái code của mọi người ứng dụng như thế nào. Nếu muốn anh cho huongchuoi vd cụ tỷ lun.


-
 
Có bài này là lấy trên GPE từ TransferData của NDU đã làm, các bạn viết cho 1 hàm Max và Min Price theo 2 điều kiện là Company Name và Services. Tuỳ chọn tại F2 và G2 của file.
Tôi mới làm ct mà ct mảng nên chậm quá, các bạn giúp tôi làm 1 UDF nhé.
Hy vọng bài loại này có nhiều áp dụng thực tế.
Cám ơn các bạn nhiều.

Bác kiểm tra giúp em
PHP:
Function MyMaxIf(ByVal rngCompany As Range, ByVal rngServices As Range, _
                 ByVal sComTest As String, ByVal sSerTest As String, ByVal rngValue As Range)
    Dim i As Long
    MyMaxIf = -9.99999999999999E+307
    For i = 1 To rngCompany.Rows.Count
        If rngCompany(i, 1) = sComTest And rngServices(i, 1) = sSerTest Then
            If MyMaxIf < rngValue(i, 1) Then
                MyMaxIf = rngValue(i, 1)
            End If
        End If
    Next
End Function
 

File đính kèm

Lần chỉnh sửa cuối:
Bác kiểm tra giúp em
PHP:
Function MyMaxIf(ByVal rngCompany As Range, ByVal rngServices As Range, _
                 ByVal sComTest As String, ByVal sSerTest As String, ByVal rngValue As Range)
    Dim i As Long
    MyMaxIf = -9.99999999999999E+307
    For i = 1 To rngCompany.Rows.Count
        If rngCompany(i, 1) = sComTest And rngServices(i, 1) = sSerTest Then
            If MyMaxIf < rngValue(i, 1) Then
                MyMaxIf = rngValue(i, 1)
            End If
        End If
    Next
End Function
Hay quá, nó giúp mình nhiều lắm, nhưng còn trường hợp khi chọn Company 02 và Service1 thì nó không ra. Vì thực tế kg có price của Company 02 và Service1.
Và giúp mình khi chọn All ở G2 là tính Max và Min theo all Service ie chỉ tính theo company thôi.
Cám ơn bạn nhiều.
 
Hay quá, nó giúp mình nhiều lắm, nhưng còn trường hợp khi chọn Company 02 và Service1 thì nó không ra. Vì thực tế kg có price của Company 02 và Service1.
Và giúp mình khi chọn All ở G2 là tính Max và Min theo all Service ie chỉ tính theo company thôi.
Cám ơn bạn nhiều.
Em nghĩ mãi không ra, có cao thủ nào gợi ý cho em chút:D
 

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

Back
Top Bottom