Những bài tập VBA đơn giản dành cho những người mới bắt đầu (1 người xem)

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

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

SA_DQ

/(hông là gì!
Thành viên danh dự
Tham gia
8/6/06
Bài viết
14,689
Được thích
23,043
Nghề nghiệp
U80

Bài 01

Macro to merge values from one column into one cell and retain source formatting.
Example:

Source:
A1= "It is going to cost "
A2= "$1000.00" (A2 is formatted to underline value)

Destination: (desired result)
B2= "It is going to cost $1000.00" (A2 value is still underlined)

Đề bài có thể tóm gọn lại như sau:

Trên cột [A:A] ta có những dòng thuyết minh & dưới nó là những con số đã được định dạng bằng nhiều cách khác nhau để fân biệt như chữ in nghiên, chữ số được tô đậm hay Font có màu đỏ,. . . .

Macro có nhiệm vụ: Hễ dòng nào có số thì ô bên fải liền kề cần được mang nội dung cũa ô trên ô có số & bản thân số của ô đang xét; Mặt khác định dạng ô giống với ô mang số liệu

Chúc thành công
--=0
--=0

Bảng liệt kê:

TT | Tên bài | Tại | Diễn giải
01|Bài tập 01|#1|Nối chuỗi & định dạng
02|Bài tập 02 | #11|Thống kê số lần lặp
03|Bài tập 03|#19|Trích lọc danh sách theo năm
04|Bài tập 04|#27|Thêm dòng theo số liệu tháng - năm
05|Bài tập 05|#31|Tổng hợp số liệu hoạt động theo từng kỳ (tháng)
06|Bài tập 06|#73|Ghí chú ngày có chi fí lớn nhất trong từng tháng khảo sát
07|Bài tập 07|#84|Thêm dòng tính tổng, sau khi đã thống kê số liệu
08|Bài tập 08|#103|Kẻ dòng, viền khung & format báo cáo hoàn chỉnh
09| BT Fần B | #206 | (Ở đây có bảng liệt kê riêng)


Rất mong các bạn ủng hộ & hỗ trợ tối đa.

! --=0 --=0 --=0
 
Chỉnh sửa lần cuối bởi điều hành viên:
Thừa nhận top này khá hay và quá là bổ ích, phát triển khá nhanh, Xin cám ơn Chủ tóp và tất cả các thầy và bạn bè anh chị em trong đại gia đình GPE đã đống gốp cho tóp này.
 
Upvote 0
Sau khi thống kê số liệu theo yêu cầu của các bài trước (Xem tại bài #41), ta cần thêm dòng tổng cộng, như sau

Mọi người giải bài tập hết rồi, em "đi sau" vậy.
Giải bài tập 7:
Mã:
Public Sub Xuan4()
Application.ScreenUpdating = False
Dim Rng As Range, Cll As Range, Dau As Long, Cuoi As Long, I As Long, TC As Double
Dim Tem As Long, SoThang As Long, Thang As Long, Mx As Double, Tong As String, Xuan As String
With Sheets("ChiFi")
    Set Rng = .Range(.[A4], .[A65000].End(xlUp))
End With
With Sheets("sheet1")
Xuan = .[B7].Value: Tong = .[B6].Value
.[A8:D1000].ClearContents
Dau = DateSerial(Year(.[C4]), Month(.[C4]), 1)
Cuoi = DateSerial(Year(.[C5]), Month(.[C5]), 1)
SoThang = DateDiff("m", Dau, Cuoi) + 1
For I = 1 To SoThang
    Mx = 0
    Thang = DateSerial(Year(Dau), Month(Dau) + I - 1, 1)
    .Cells(I + 7, 1).Value = I
    .Cells(I + 7, 2).Value = Xuan & " " & Format(Thang, "mm/yyyy")
    For Each Cll In Rng
        If Cll >= .[C4] And Cll <= .[C5] Then
                Tem = DateSerial(Year(Cll), Month(Cll), 1)
            If Tem = Thang Then
                .Cells(I + 7, 3).Value = .Cells(I + 7, 3).Value + Cll.Offset(, 4).Value
                TC = TC + Cll.Offset(, 4).Value
                If Mx < Cll.Offset(, 4).Value Then
                    Mx = Cll.Offset(, 4).Value
                    .Cells(I + 7, 4).Value = Cll.Value
                End If
            End If
        End If
    Next
Next I
End With
Range("B65000").End(xlUp).Offset(1).Value = Tong
Range("B65000").End(xlUp).Offset(, 1).Value = TC
Set Rng = Nothing
Application.ScreenUpdating = True
End Sub
 

File đính kèm

Upvote 0
Bài tập số 8: Kẻ dòng, viền khung bảng dữ liệu theo thẩm mỹ mỗi người & . . . .

(*) Thêm dưới khung viền fía fải là (Địa điểm & ngày tháng năm (lập B/C))

(*) Thêm dòng <Người lập bảng> & <Người kiểm soát.> cân đối trong bảng B/C


(Đến giờ các bạn sẽ thấy rằng công việc sẽ giảm thiểu, nếu ta không quá lệ thuộc vô VBA)


Gần xong loạt bài này rồi, & chúc các bạn nhiều thành công!
 
Upvote 0
Thủ tục này hơi lạ hen! Sao lại Selection.AutoFilter ở dòng đầu và dòng cuối nhỉ? Tác dụng của nó là gì và nó lọc cái gì vậy?
uh hen thủ tục trên là thừa rùi như vậy chắc là được:
PHP:
Sub tong2()
[B5:B997].SpecialCells(4).EntireRow.Hidden = True
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn bạn Nghĩa, mình viết được thế đã đủ "tắc thở", Thấy nó chạy, không chống lại là mừng rồi . Học thêm được món bỏ "cam quýt" của bạn, chạy cho nhanh . Mình nhớ rồi ! xin cám ơn bạn .

Nói như vậy chưa phải là chuẩn, dùng with đôi khi lại nhanh hơn chứ không phải làm chậm. Tôi nói code của bạn chậm là vì bạn dùng nhiều cách để thực hiện một hành động. Mục đích của bạn là từ A đến kết kết quả D, bạn lại phải đi vòng vèo từ A > B > C > D thay vì chỉ cần đi tắt A > D mà không cần thông qua 2 chặng đường B và C.

Khi nào dùng With và khi nào không? Khi một object, một control hay một cái gì đó xảy ra nhiều hành động, sự kiện trên chính nó thì ta dùng with. Thông thường thì từ 3 sự việc liên quan đến nó thì ta nên dùng with để code nó ngắn gọn dễ hiểu và tường minh.

Ví dụ, khi ta viết về một thủ tục trên một cell, về định dạng chẳng hạn:

Thay vì ta viết như vầy, tuy nó chẳng sai tí nào cả:

Mã:
Sub Macro1()

    Range("C5").Select
    Range("C5").Font.ColorIndex = 3
    Range("C5").Interior.ColorIndex = 38
    Range("C5").Interior.Pattern = xlSolid
    Range("C5").HorizontalAlignment = xlCenter
    Range("C5").VerticalAlignment = xlBottom
    Range("C5").WrapText = False
    Range("C5").Orientation = 0
    Range("C5").AddIndent = False
    Range("C5").IndentLevel = 0
    Range("C5").ShrinkToFit = False
    Range("C5").ReadingOrder = xlContext
    Range("C5").MergeCells = False
    Range("C5").Font.Bold = True
    Range("C5").Font.Italic = True
    Range("C5").Font.Underline = xlUnderlineStyleSingle
    Range("C5").Borders(xlDiagonalDown).LineStyle = xlNone
    Range("C5").Borders(xlDiagonalUp).LineStyle = xlNone
End Sub

Thì ta có thể dùng with như sau:

Mã:
Sub Macro1()
    With Range("C5")
        .Select
        .HorizontalAlignment = xlCenter
        .VerticalAlignment = xlBottom
        .WrapText = False
        .Orientation = 0
        .AddIndent = False
        .IndentLevel = 0
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = False
        .Borders(xlDiagonalDown).LineStyle = xlNone
        .Borders(xlDiagonalUp).LineStyle = xlNone
        
        With .Interior
            .ColorIndex = 38
            .Pattern = xlSolid
        End With
        
        With .Font
            .ColorIndex = 3
            .Bold = True
            .Italic = True
            .Underline = xlUnderlineStyleSingle
        End With
    End With
End Sub

Vì thế, đôi khi thiếu vitamin C ta nên ăn cam quýt cho ta có đủ khoáng chất là như vậy!
 
Upvote 0
Nói như vậy chưa phải là chuẩn, dùng with đôi khi lại nhanh hơn chứ không phải làm chậm. Tôi nói code của bạn chậm là vì bạn dùng nhiều cách để thực hiện một hành động. Mục đích của bạn là từ A đến kết kết quả D, bạn lại phải đi vòng vèo từ A > B > C > D thay vì chỉ cần đi tắt A > D mà không cần thông qua 2 chặng đường B và C.

Vì thế, đôi khi thiếu vitamin C ta nên ăn cam quýt cho ta có đủ khoáng chất là như vậy!

Thực ra khi bắt đầu học, em nghĩ là phải đi từng bước, từ A ->B->C->D. Khi nẵm rõ bản chất mới có thể "đi tắt, đón đầu". Việc "đốt cháy giai đoạn" cũng tốt nhưng sẽ khó cho những người mới bắt đầu.

(tuy nhiên cũng tùy người, có những người học theokiểu "đốt cháy giai đoạn" vẫn tiếp thu tốt kiến thức như ...anh Ếch Xanh đó...hihihi)
Thiếu vitamin C, ăn nhiều thứ cho thêm chất, nhưng ăn nhiều quá sẽ bội thực và nhai không kỹ sẽ đau dạ dày. Hic hic...
 
Lần chỉnh sửa cuối:
Upvote 0
Nói như vậy chưa phải là chuẩn, dùng with đôi khi lại nhanh hơn chứ không phải làm chậm. Tôi nói code của bạn chậm là vì bạn dùng nhiều cách để thực hiện một hành động. Mục đích của bạn là từ A đến kết kết quả D, bạn lại phải đi vòng vèo từ A > B > C > D thay vì chỉ cần đi tắt A > D mà không cần thông qua 2 chặng đường B và C.

Khi nào dùng With và khi nào không? Khi một object, một control hay một cái gì đó xảy ra nhiều hành động, sự kiện trên chính nó thì ta dùng with. Thông thường thì từ 3 sự việc liên quan đến nó thì ta nên dùng with để code nó ngắn gọn dễ hiểu và tường minh.

Ví dụ, khi ta viết về một thủ tục trên một cell, về định dạng chẳng hạn:

Thay vì ta viết như vầy, tuy nó chẳng sai tí nào cả:

Mã:
Sub Macro1()

    Range("C5").Select
    Range("C5").Font.ColorIndex = 3
    Range("C5").Interior.ColorIndex = 38
    Range("C5").Interior.Pattern = xlSolid
    Range("C5").HorizontalAlignment = xlCenter
    Range("C5").VerticalAlignment = xlBottom
    Range("C5").WrapText = False
    Range("C5").Orientation = 0
    Range("C5").AddIndent = False
    Range("C5").IndentLevel = 0
    Range("C5").ShrinkToFit = False
    Range("C5").ReadingOrder = xlContext
    Range("C5").MergeCells = False
    Range("C5").Font.Bold = True
    Range("C5").Font.Italic = True
    Range("C5").Font.Underline = xlUnderlineStyleSingle
    Range("C5").Borders(xlDiagonalDown).LineStyle = xlNone
    Range("C5").Borders(xlDiagonalUp).LineStyle = xlNone
End Sub

Thì ta có thể dùng with như sau:

Mã:
Sub Macro1()
    With Range("C5")
        .Select
        .HorizontalAlignment = xlCenter
        .VerticalAlignment = xlBottom
        .WrapText = False
        .Orientation = 0
        .AddIndent = False
        .IndentLevel = 0
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = False
        .Borders(xlDiagonalDown).LineStyle = xlNone
        .Borders(xlDiagonalUp).LineStyle = xlNone
        
        With .Interior
            .ColorIndex = 38
            .Pattern = xlSolid
        End With
        
        With .Font
            .ColorIndex = 3
            .Bold = True
            .Italic = True
            .Underline = xlUnderlineStyleSingle
        End With
    End With
End Sub

Vì thế, đôi khi thiếu vitamin C ta nên ăn cam quýt cho ta có đủ khoáng chất là như vậy!
Trời ơi! không phải "Tắc thở" mà là "Tắc tử" luôn. Cám ơn bạn! Thực ra là cám ơn "thầy" thì đúng hơn, Nhưng thấy chiêu bài "Độc thân,vui tính" nhà em không dám chào là thầy, sợ có cô nào rắp tâm "nhòm" đến lại chạy "mất dép" thì khổ; Thực ra có người phụ nữ ở bên cạnh, lắm lúc "hay" đáo để.
Người ta nói "Trâu con không sợ hổ", nhà em cứ xông ra, nếu "đụng" phải ai, người đó chịu, không tránh trẻ con, tự mình có lỗi nhé .
 
Lần chỉnh sửa cuối:
Upvote 0
Mọi người giải bài tập hết rồi, em "đi sau" vậy.
Giải bài tập 7:

Code của XN82 đã thực hiện xong các nhiệm vụ đề ra. Nhưng có thể cải tiến để tăng tốc độ hơn, theo gợi í sau:

Ta tính ra được mốc thời gian đầu & cuối của từng kỳ/tháng; 2 trị này cung cấp cho vùng Criteria & lọc số liệu kỳ/tháng đó ra 1 vùng trống nào đó;

Sau khi lọc rồi thì ta có thể xài hàm SUMIF() như chàng độc thân Ba Tê, hay DSUM() (mình khoái khẩu) để tính & điền vô bảng biểu báo cáo;
(Nói là khoái khẩu vì ta có thể xài DMAX() để hoàn thành #7 1 cách trọn vẹn mà chưa cần đến E2007)

Lúc nào rỗi, bạn nào thử xem sao (!?!)

Lúc đó ta có số liệu về thời lượng cho mỗi 1 fương cách của chúng ta; & như vậy sự thích thú VBA sẽ ta lên trong ta!

(húc thành công.
 
Upvote 0
Thực ra khi bắt đầu học, em nghĩ là phải đi từng bước, từ A ->B->C->D. Khi nẵm rõ bản chất mới có thể "đi tắt, đón đầu". Việc "đốt cháy giai đoạn" cũng tốt nhưng sẽ khó cho những người mới bắt đầu.

(tuy nhiên cũng tùy người, có những người học theo kiểu "đốt cháy giai đoạn" vẫn tiếp thu tốt kiến thức như ...anh Ếch Xanh đó...hihihi)
Thiếu vitamin C, ăn nhiều thứ cho thêm chất, nhưng ăn nhiều quá sẽ bội thực và nhai không kỹ sẽ đau dạ dày. Hic hic...

Thật ra With ... End With là một anh đại diện cho một đối tượng nào đó, anh này cũng sẽ không chịu trách nhiệm nếu hành động liên quan đến anh ta mà không có dấu chấm (.) đứng trước hành động của mình. Thấy dấu chấm tức là anh ta nhận nhiệm vụ, còn không anh ta bỏ qua hoặc thậm chí còn cự nự lên nữa!

Việc này ta nên đốt cháy giai đoạn vì bản chất của nó cũng không có gì là quá khó khăn phải không!

Liên quan đến nó còn có việc khai báo biến, anh biến này (chẳng phải anh ta làm biếng đâu nha) cũng là một đại diện cho một kiểu data type nào đó mà sau này bác Sa sẽ hướng dẫn cho các bạn.
 
Upvote 0
Code của XN82 đã thực hiện xong các nhiệm vụ đề ra. Nhưng có thể cải tiến để tăng tốc độ hơn, theo gợi í sau:

Ta tính ra được mốc thời gian đầu & cuối của từng kỳ/tháng; 2 trị này cung cấp cho vùng Criteria & lọc số liệu kỳ/tháng đó ra 1 vùng trống nào đó;

Sau khi lọc rồi thì ta có thể xài hàm SUMIF() như chàng độc thân Ba Tê, hay DSUM() (mình khoái khẩu) để tính & điền vô bảng biểu báo cáo;
(Nói là khoái khẩu vì ta có thể xài DMAX() để hoàn thành #7 1 cách trọn vẹn mà chưa cần đến E2007)

Lúc nào rỗi, bạn nào thử xem sao (!?!)

Lúc đó ta có số liệu về thời lượng cho mỗi 1 fương cách của chúng ta; & như vậy sự thích thú VBA sẽ ta lên trong ta!

(húc thành công.
Em thấy dùng ado tốc độ cũng không đến nổi chậm mà anh?
 
Upvote 0
Upvote 0
Upvote 0
Bạn nghĩ ADO đơn giản hơn VBA sao? Nếu bạn có sẳn cái sườn và thay thế, lắp ghép vào thì đó cũng là chuyện dễ, tuy nhiên, bạn biết bản chất của nó như thế nào không? Mình chỉ hỏi ở mức độ bạn hiểu về nó.
Bản chất là sao bạn? Mức độ hiểu của mình chỉ đủ để áp dụng cho đề bài này, vậy theo bạn bản chất của nó là gì? Bạn nói có cái sườn rồi lắp ghép vào? vậy muốn lắp ghép vào thì có hiểu mới có thể lắp ghép. Tôi không nói ADO đơn giản hơn VBA mà tôi chỉ muốn nói là tôi muốn đưa ra 1 trong muôn triệu cách để giải quyết vấn đề. Bạn hiểu chứ?
 
Upvote 0
Bản chất là sao bạn? Mức độ hiểu của mình chỉ đủ để áp dụng cho đề bài này, vậy theo bạn bản chất của nó là gì? Bạn nói có cái sườn rồi lắp ghép vào? vậy muốn lắp ghép vào thì có hiểu mới có thể lắp ghép. Tôi không nói ADO đơn giản hơn VBA mà tôi chỉ muốn nói là tôi muốn đưa ra 1 trong muôn triệu cách để giải quyết vấn đề. Bạn hiểu chứ?

ADO là một dạng, nôm na là "siêu liên kết", nó có thể kết nối ngay trên file đang đóng và lấy dữ liệu trên đó. Có thể nói rằng sử dụng nó để lấy dữ liệu, truy xuất dữ liệu từ một file đang mở, liên kết với một file đang không hoạt động thì đó chính là sức mạnh của ADO.

Quay lại với code của VBA nó hoạt động trên những file đang mở và chỉ lấy được dữ liệu của file đang được kích hoạt mà thôi. Vậy thì, ngay tại file mình đang mở và mình thực hiện ngay chính trên file này thì mình không cần gì phải dùng ADO để thực hiện công việc của mình. Điều đó cũng giống như là: một căn nhà có 2 phòng, thay vì từ phòng này mình mở cửa phòng kia bằng chìa khóa mình sẳn có để vào thì mình lại chạy một vòng rồi tìm anh thợ mở khóa để mở ngay cái phòng đó mà mình đang giữ chìa khóa.

Như thế giống như việc "Dùng dao mỗ trâu để cắt cổ gà" vậy đó bạn.

tôi muốn đưa ra 1 trong muôn triệu cách để giải quyết vấn đề

Ngay chính công thức trên sheet, dùng hàm SUM, SUMIF, SUBTOTAL, SUMPRODUCT... thậm chí cộng từng mục cũng đều cho ra kết quả như nhau, vậy sao ta không chọn hàm SUM để làm cái rẹt cho xong nhỉ?

Huống chi tiêu đề của topic này là "dành cho người mới bắt đầu", sao mình phải đưa trường hợp dùng ADO vào trong đây?
 
Lần chỉnh sửa cuối:
Upvote 0
(*) Thêm dưới khung viền fía fải là (Địa điểm & ngày tháng năm (lập B/C))

(*) Thêm dòng <Người lập bảng> & <Người kiểm soát.> cân đối trong bảng B/C


(Đến giờ các bạn sẽ thấy rằng công việc sẽ giảm thiểu, nếu ta không quá lệ thuộc vô VBA)


Gần xong loạt bài này rồi, & chúc các bạn nhiều thành công!

Tiếp tục bài 8 (Hic, em chỉ kẻ vẽ khung viền được như thế này thôi)

Mã:
Sub Xuan5()
Worksheets("Sheet1").Activate
With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
.Borders.LineStyle = xlContinuous
 End With
With Range("B1000").End(xlUp)
 .Offset(1, 1) = "Ngay        thang          nam"
 .Offset(2) = "Nguoi Lap Bang"
 .Offset(2, 2) = "Nguoi Kiem Soat"
 End With
 End Sub
 

File đính kèm

Upvote 0
ADO là một dạng, nôm na là "siêu liên kết", nó có thể kết nối ngay trên file đang đóng và lấy dữ liệu trên đó. Có thể nói rằng sử dụng nó để lấy dữ liệu, truy xuất dữ liệu từ một file đang mở, liên kết với một file đang không hoạt động thì đó chính là sức mạnh của ADO.

Quay lại với code của VBA nó hoạt động trên những file đang mở và chỉ lấy được dữ liệu của file đang được kích hoạt mà thôi. Vậy thì, ngay tại file mình đang mở và mình thực hiện ngay chính trên file này thì mình không cần gì phải dùng ADO để thực hiện công việc của mình. Điều đó cũng giống như là: một căn nhà có 2 phòng, thay vì từ phòng này mình mở cửa phòng kia bằng chìa khóa mình sẳn có để vào thì mình lại chạy một vòng rồi tìm anh thợ mở khóa để mở ngay cái phòng đó mà mình đang giữ chìa khóa.

Như thế giống như việc "Dùng dao mỗ trâu để cắt cổ gà" vậy đó bạn.
Việc kết nối hay truy vấn thì ai mà chẳng biết nhưng bạn dùng từ "Bản chất" tôi chưa hiểu cái "Bản chất" mà bạn diễn tả. Còn việc dùng dao mổ trâu để giết gà thì mình cho rằng là bạn dùng cảm quan của bạn để mà phán đoán 1 cách phiếm diện. Việc kết nối và truy vấn với tốc độ nhanh như thế thì tội gì mà chẳng dùng nó, điều này chắc bạn hiểu nhỉ. Bạn lấy ví dụ về căn phòng tôi thấy tức cười quá, nó đâu ăn nhập gì đến cái này, cái chìa khóa của 2 căn phòng đó bạn đang giữ mà chìa khóa đó có nhiều loại, chìa khóa của chính nó hay là chìa khóa vạn năng... Cho dù là chìa khóa nào đi nữa thì mục đích cuối cùng là mở được cửa phòng đó nhanh gọn lẹ là được. Bạn hiểu ý tôi muốn nói gì chư?
 
Lần chỉnh sửa cuối:
Upvote 0
Tiếp tục bài 8 (Hic, em chỉ kẻ vẽ khung viền được như thế này thôi)

Mã:
Sub Xuan5()
Worksheets("Sheet1").Activate
With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
.Borders.LineStyle = xlContinuous
 End With
With Range("B1000").End(xlUp)
 .Offset(1, 1) = "Ngay        thang          nam"
 .Offset(2) = "Nguoi Lap Bang"
 .Offset(2, 2) = "Nguoi Kiem Soat"
 End With
 End Sub

Hi Hi , cái code này bấm 2 lần sao nhỉ
---------------
Spam 1 tý, mình cũng đang học hỏi đó!
 
Upvote 0
Phía trên mình cũng có đề nghị dùng các thuật toán cơ bản để những người còn yếu như mình theo cho kip. Thấy bài ADO mình sững sờ rơi lệ luôn đó.
 
Upvote 0
Ngay chính công thức trên sheet, dùng hàm SUM, SUMIF, SUBTOTAL, SUMPRODUCT... thậm chí cộng từng mục cũng đều cho ra kết quả như nhau, vậy sao ta không chọn hàm SUM để làm cái rẹt cho xong nhỉ?

Huống chi tiêu đề của topic này là "dành cho người mới bắt đầu", sao mình phải đưa trường hợp dùng ADO vào trong đây?
Bạn nói như thế sao được, nếu trên sheet có các hàm này và có cả những công cụ để mà thực hiện ý đồ của bạn thì tội gì bạn dùng VBA? Cũng như bạn nói dùng ADO là dao mổ trâu? Vậy VBA so với công cụ sẵn có và Hàm thì sẽ như thế nào?
ADO và cả VBA thì tôi mới bắt đầu học. Việc mới bắt đầu học như tôi thì đâu có vi phạm phải không bạn?
 
Upvote 0
Tiếp tục bài 8 (Hic, em chỉ kẻ vẽ khung viền được như thế này thôi)

Mã:
Sub Xuan5()
Worksheets("Sheet1").Activate
With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
.Borders.LineStyle = xlContinuous
 End With
With Range("B1000").End(xlUp)
 .Offset(1, 1) = "Ngay        thang          nam"
 .Offset(2) = "Nguoi Lap Bang"
 .Offset(2, 2) = "Nguoi Kiem Soat"
 End With
 End Sub

Tiến bộ rồi đấy, mình góp ý một tí nhé! Trước tiên về định dạng và cách đặt giá trị vào cell thì code này đã thực hiện tốt. Tuy nhiên, như tôi đã nói ở bài trước:

tại phần này:

Mã:
With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
.Borders.LineStyle = xlContinuous
 End With

Nếu chỉ dùng địa chỉ ô, khối ô đó cho một hành động là Borders thì ta không cần dùng đến with để code ngắn gọn hơn. Với thủ tục trên ta chỉ cần như thế này:

Mã:
Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4).Borders.LineStyle = xlContinuous

Nhưng bạn sẽ nói nhìn nó dài thòn khó coi quá, không sao đâu, VBA có "cửa" để cho bạn xuống hàng một cách hợp lý, chỉ cần cách khoảng một ký tự, rồi thêm một dấu gạch chân (_) là ta có thể xuống hàng để câu lệnh được tiếp tục:

Mã:
    Range([B8], [B1000].End(xlUp)).Offset(, -1)[COLOR=#ff0000] _[/COLOR]
    .Resize(, 4).Borders.LineStyle = xlContinuous

Với thủ tục của XN, tôi hướng dẫn các bạn sử dụng biến để lấy giá trị dòng kiểu LONG như sau:

Mã:
Sub Xuan5_2()
    Worksheets("Sheet1").Activate
    [COLOR=#008000]'khai báo biến dạng Long (tham khảo Data Type trong Help của VBA)[/COLOR]
    [COLOR=#0000cd]Dim [/COLOR][COLOR=#ff0000]iRow [/COLOR][COLOR=#0000cd]As Long[/COLOR]
   [COLOR=#008000] 'lấy giá trị hàng của Range tìm được và gán cho biến[/COLOR]
    iRow = Range("B1000").End(xlUp).Row
    [COLOR=#008000]'Ghép biến đó cho "khối" cell    [/COLOR]
    Range("A8:D" & [COLOR=#ff0000]iRow[/COLOR]).Borders.LineStyle = xlContinuous
   [COLOR=#008000] 'cũng biến đó ghép vào 1 cell[/COLOR]
    With Range("B" & [COLOR=#ff0000]iRow[/COLOR])
        .Offset(1, 1) = "Ngay        thang          nam"
        .Offset(2) = "Nguoi Lap Bang"
        .Offset(2, 2) = "Nguoi Kiem Soat"
    End With
End Sub

Như thủ tục trên, bạn sẽ bớt đi 1 công đoạn Range("B1000").End(xlUp).

Đó cũng là một cách bạn tư duy để làm cho code hoạt động hiệu quả.

Hi Hi , cái code này bấm 2 lần sao nhỉ
---------------
Spam 1 tý, mình cũng đang học hỏi đó!

Đây là bài bạn XN thực hành thôi, mà thực hành nào cũng khó trọn vẹn, bản thân tôi khi thực hành còn treo máy, mất dữ liệu tùm lum đấy thôi! Từ những kinh nghiệm "đau thương" đó mình sẽ tự biết cột nào, vùng nào là "bất khả xâm phạm", làm vùng chính để mình thực thi code, còn không thì lỗi có thể xảy ra một cách đáng tiếc.

Hy vọng các bạn mới bước vào môi trường VBA sẽ tự biết tư duy, tùy biến để code của mình đạt được tối ưu nhất.
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Hi Hi , cái code này bấm 2 lần sao nhỉ
---------------
Spam 1 tý, mình cũng đang học hỏi đó!

Hic, mình mới chỉ "nhập môn" VBA thôi, trình còn non lắm. Thậm chí mới chỉ biết từ A phải đi tới B rồi mới tới C chứ chưa biết rút ngọn, đi tắt thế nào cho nhanh. Và chưa thể nào hoàn chỉnh được với code của mình.
Nếu ai đó có nhã ý và thấy code của mình chưa hoàn chỉnh, xin nêu lên góp ý, còn nói chung chung, mình cũng hổng hiểu luôn.
Thầy giáo mình chưa cho mình tốt nghiệp lớp mẫu giáo VBA, nên mình còn phải học hỏi nhiều.
Cảm ơn các thầy và các bạn!
 
Lần chỉnh sửa cuối:
Upvote 0
Việc kết nối hay truy vấn thì ai mà chẳng biết nhưng bạn dùng từ "Bản chất" tôi chưa hiểu cái "Bản chất" mà bạn diễn tả. Còn việc dùng dao mổ trâu để giết gà thì mình cho rằng là bạn dùng cảm quan của bạn để mà phán đoán 1 cách phiếm diện. Việc kết nối và truy vấn với tốc độ nhanh như thế thì tội gì mà chẳng dùng nó, điều này chắc bạn hiểu nhỉ. Bạn lấy ví dụ về căn phòng tôi thấy tức cười quá, nó đâu ăn nhập gì đến cái này, cái chìa khóa của 2 căn phòng đó bạn đang giữ mà chìa khóa đó có nhiều loại, chìa khóa của chính nó hay là chìa khóa vạn năng... Cho dù là chìa khóa nào đi nữa thì mục đích cuối cùng là mở được cửa phòng đó nhanh gọn lẹ là được. Bạn hiểu ý tôi muốn nói gì chư?

Tôi không muốn lý sự với bạn ở đây, nếu muốn về ADO thì vào mà thảo luận tại bài đó và bạn muốn bắt đầu từ đó thì Hai Lúa Miền Tây hoặc những người giỏi về CSDL như Levanduyet sẽ hướng dẫn bạn một cách cụ thể, khái quát, còn ở đây là topic VBA cho người mới bắt đầu.

Set cnn = CreateObject("ADODB.Connection")
Set lrs = CreateObject("ADODB.Recordset")

Thế bạn biết bản chất của 2 câu này như thế nào chưa? Nó ở đâu và nó từ thư viện nào hay không? Bản chất là ở chỗ bạn hiểu nó như thế nào để bạn ứng dụng vào, chứ không phải người ta đặt code sẳn, sau đó bạn điền vào chỗ trống những range, những số liệu vô đó đâu bạn!
 
Upvote 0
Đây là bài bạn XN thực hành thôi, mà thực hành nào cũng khó trọn vẹn, bản thân tôi khi thực hành còn treo máy, mất dữ liệu tùm lum đấy thôi! Từ những kinh nghiệm "đau thương" đó mình sẽ tự biết cột nào, vùng nào là "bất khả xâm phạm", làm vùng chính để mình thực thi code, còn không thì lỗi có thể xảy ra một cách đáng tiếc.

Hy vọng các bạn mới bước vào môi trường VBA sẽ tự biết tư duy, tùy biến để code của mình đạt được tối ưu nhất.
xuan.nguyen82

Hic, mình mới chỉ "nhập môn" VBA thôi, trình còn non lắm. Thậm chí mới chỉ biết từ A phải đi tới B rồi mới tới C chứ chưa biết rút ngọn, đi tắt thế nào cho nhanh. Và chưa thể nào hoàn chỉnh được với code của mình.
Nếu ai đó có nhã ý và thấy code của mình chưa hoàn chỉnh, xin nêu lên góp ý, còn nói chung chung, mình cũng hổng hiểu luôn.
Thầy giáo mình chưa cho mình tốt nghiệp lớp mẫu giáo VBA, nên mình còn phải học hỏi nhiều.
Cảm ơn các thầy và các bạn!
Hi, cái này em kg có ý gì! chỉ đang muốn học thôi mà, em có biết code kiết gì đâu!
Chỉ thấy bấm code từ 2 lần trở lên Thì thấy mấy tiêu đề "Ngay tháng"... nó lập lại nữa mà. Chỉ mong các thầy & anh chị chỉ dẫn để nó khỏi lập lại thôi
Em cảm ơn!
 
Upvote 0
Tôi không muốn lý sự với bạn ở đây, nếu muốn về ADO thì vào mà thảo luận tại bài đó và bạn muốn bắt đầu từ đó thì Hai Lúa Miền Tây hoặc những người giỏi về CSDL như Levanduyet sẽ hướng dẫn bạn một cách cụ thể, khái quát, còn ở đây là topic VBA cho người mới bắt đầu.

Set cnn = CreateObject("ADODB.Connection")
Set lrs = CreateObject("ADODB.Recordset")

Thế bạn biết bản chất của 2 câu này như thế nào chưa? Nó ở đâu và nó từ thư viện nào hay không? Bản chất là ở chỗ bạn hiểu nó như thế nào để bạn ứng dụng vào, chứ không phải người ta đặt code sẳn, sau đó bạn điền vào chỗ trống những range, những số liệu vô đó đâu bạn!

Một thành viên mới mà có kiến thức về ADO cũng rất đáng nể. Mỗi người có 1 cách giải quyết vấn đề và cách nhìn nhận vấn đề khác nhau. Bạn ấy cũng chỉ là đưa ra 1 phương pháp giải quyết cùng 1 đề bài. Em nghĩ nên để thành viên mới thoải mái đưa ra ý kiến của mình, có thể mở rộng kiến thức hoặc đưa ra những cách giải quyết khác nhau.
 
Upvote 0
Hi, cái này em kg có ý gì! chỉ đang muốn học thôi mà, em có biết code kiết gì đâu!
Chỉ thấy bấm code từ 2 lần trở lên Thì thấy mấy tiêu đề "Ngay tháng"... nó lập lại nữa mà. Chỉ mong các thầy & anh chị chỉ dẫn để nó khỏi lập lại thôi
Em cảm ơn!

Trời ơi, nói "không có biết code kiết gì đâu" là không đúng, mình đọc nhiều bài của bạn về code rồi. Tuy nhiên vì mình mới học nên sẽ có nhiều lỗi khi chạy code. Cảm ơn sự góp ý của bạn. Mỗi một lời góp ý của các bạn là kiến thức bổ ích cho những người như mình.
 
Upvote 0
Tôi không muốn lý sự với bạn ở đây, nếu muốn về ADO thì vào mà thảo luận tại bài đó và bạn muốn bắt đầu từ đó thì Hai Lúa Miền Tây hoặc những người giỏi về CSDL như Levanduyet sẽ hướng dẫn bạn một cách cụ thể, khái quát, còn ở đây là topic VBA cho người mới bắt đầu.

Set cnn = CreateObject("ADODB.Connection")
Set lrs = CreateObject("ADODB.Recordset")


Thế bạn biết bản chất của 2 câu này như thế nào chưa? Nó ở đâu và nó từ thư viện nào hay không? Bản chất là ở chỗ bạn hiểu nó như thế nào để bạn ứng dụng vào, chứ không phải người ta đặt code sẳn, sau đó bạn điền vào chỗ trống những range, những số liệu vô đó đâu bạn!
Đúng ra nếu 2 dòng trên không có cũng được, bạn đừng cho rằng là chỉ mình biết còn người mới tham gia như mình chẳng biết tí gì về nó. 2 câu trên nếu không khai báo thì sẽ mất công tham chiếu trong thư viện của Microsoft ActiveX Data Objects x.x Library. Nếu tham chiếu như thế này thì sẽ dể cho người lập trình nhưng ngược lại sẽ gây khó cho người sử dụng. Điều này là căn bản cho người dùng ADO sao bạn lại hỏi tôi câu này?
 
Upvote 0
Hi, cái này em kg có ý gì! chỉ đang muốn học thôi mà, em có biết code kiết gì đâu!
Chỉ thấy bấm code từ 2 lần trở lên Thì thấy mấy tiêu đề "Ngay tháng"... nó lập lại nữa mà. Chỉ mong các thầy & anh chị chỉ dẫn để nó khỏi lập lại thôi
Em cảm ơn!
Thêm điều kiện củ chuối này vậy:
If Range("B" & iRow) <> "Nguoi Lap Bang" Then
PHP:
Sub Xuan5_2()    
Worksheets("Sheet1").Activate  
  'khai báo bi?n d?ng Long (tham kh?o Data Type trong Help c?a VBA)   
 Dim iRow As Long  
  'l?y giá tr? hàng c?a Range tìm du?c và gán cho bi?n
    iRow = Range("B1000").End(xlUp).Row  
  If Range("B" & iRow) <> "Nguoi Lap Bang" Then  
  'Ghép bi?n dó cho "kh?i" cell  
  Range("A8:D" & iRow).Borders.LineStyle = xlContinuous 
   'cung bi?n dó ghép vào 1 cell    
    With Range("B" & iRow)    
    .Offset(1, 1) = "Ngay        thang          nam"      
  .Offset(2) = "Nguoi Lap Bang"      
  .Offset(2, 2) = "Nguoi Kiem Soat"  
  End With   
 End If
End Sub
 
Upvote 0
Như thủ tục trên, bạn sẽ bớt đi 1 công đoạn Range("B1000").End(xlUp).

Đó cũng là một cách bạn tư duy để làm cho code hoạt động hiệu quả.
Có thể dùng SpecialCells để xác định dòng cuối cùng của dữ liệu, tuy nhiên mỗi cách đều có ưu và khuyết khác nhau, quan trọng là biết cách vận dụng cho phù hợp với csdl.
 
Upvote 0
Tiếp tục bài 8 (Hic, em chỉ kẻ vẽ khung viền được như thế này thôi)

Mã:
Sub Xuan5()
Worksheets("Sheet1").Activate
With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
.Borders.LineStyle = xlContinuous
 End With
With Range("B1000").End(xlUp)
 .Offset(1, 1) = "Ngay        thang          nam"
 .Offset(2) = "Nguoi Lap Bang"
 .Offset(2, 2) = "Nguoi Kiem Soat"
 End With
 End Sub
Tôi thấy dòng thứ 3 With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
nên sửa thành With Range([B7], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
để đóng khung cả tiêu đề .
và Public Sub Xuan4()
dòng thứ 10 .[A8:D1000].ClearContents
nên sửa thành .[A8:D1000].Clear
vì nếu dữ liệu lần lọc sau nhỏ hơn lần lọc trước, Boder sẽ không được xóa , vì dòng lệnh trên chỉ xóa nội dung.
 
Upvote 0
Tôi thấy dòng thứ 3 With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
nên sửa thành With Range([B7], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
để đóng khung cả tiêu đề .
và Public Sub Xuan4()
dòng thứ 10 .[A8:D1000].ClearContents
nên sửa thành .[A8:D1000].Clear
vì nếu dữ liệu lần lọc sau nhỏ hơn lần lọc trước, Boder sẽ không được xóa , vì dòng lệnh trên chỉ xóa nội dung.
Còn 1 cách tuy nó mất công nhưng cũng khá hiệu quả về cách tạo tiêu đề cuối trang đó là phải thiết kế cái chân tiêu đề đó, lưu vào nơi nào đó, xong copy và dán phía dưới cuối cùng của bảng kết quả.
 
Upvote 0
Tôi thấy dòng thứ 3 With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
nên sửa thành With Range([B7], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
để đóng khung cả tiêu đề .
và Public Sub Xuan4()
dòng thứ 10 .[A8:D1000].ClearContents
nên sửa thành .[A8:D1000].Clear
vì nếu dữ liệu lần lọc sau nhỏ hơn lần lọc trước, Boder sẽ không được xóa , vì dòng lệnh trên chỉ xóa nội dung.

Mặc dù tùy vào dữ liệu mà đặt số dòng cuối cùng, nhưng các bạn cũng nên tập thói quen lấy dòng cuối cùng của sheet để chạy code. Với Excel 2003 thì các bạn chọn dòng cuối là 65536 để mình End(xlUp). Bây giờ, mặc dù tôi đang sử dụng cả 2 loại 2003-2007 nhưng dù viết bên nào tôi cũng chọn dòng cuối là 65536 vì khi đó mình có thể chuyển qua định dạng từ 2007 qua 2003 code cũng không bị lỗi. Với số dòng như thế thì cũng khó có CSDL trên excel nào lên được tới đó.

Mặt khác, nếu chỉ để áng dòng là 1000 thì có thể có một lỗi đáng tiếc là tràn dòng. Vì thế nên chọn dòng cuối cùng của sheet mà thực thi code.

Hi, cái này em kg có ý gì! chỉ đang muốn học thôi mà, em có biết code kiết gì đâu!
Chỉ thấy bấm code từ 2 lần trở lên Thì thấy mấy tiêu đề "Ngay tháng"... nó lập lại nữa mà. Chỉ mong các thầy & anh chị chỉ dẫn để nó khỏi lập lại thôi
Em cảm ơn!

Cái câu tô đậm là bạn đang khiêm tốn đấy, nhưng thiết nghĩ, đã bước vào lập trình thì mọi người luôn luôn nghĩ trong đầu phải học cách BẪY LỖI. Nếu lập trình mà không bẫy lỗi thì chỉ có VBA "thô" thôi. Cho nên câu hỏi của bạn cũng rất đáng được chú ý đối với các học viên mới.

Giả sử tôi có Sheet1 và một cơ sở dữ liệu, bắt đầu từ dòng 4 là dòng tiêu đề, tôi muốn các bạn xóa dữ liệu (ClearContents) từ dòng 5 trở đi, không xóa tiêu đề nha các bạn.

Điều kiện:

HÃY ĐỂ CÁC BẠN MỚI HỌC THỰC HIỆN, CÁC BẠN "LÃO LÀNG" XIN VUI LÒNG ĐỢI CÁC BẠN MỚI HỌC LÀM XONG VÀI BÀI RỒI HÃY GÓP Ý VÀ TRUYỀN ĐẠT THÊM SAU NHÉ.

- Lấy cột A làm chuẩn.

- Dùng phương thức End(xlUp) để dò hàng cuối cùng của cột A rồi từ cột A các bạn tính hay xác định đến các cột khác để xóa dữ liệu.

- Sau khi hoàn tất thủ tục, gán macro xóa đó vào nút lệnh có sẳn (Xóa hàng).

- Bấm nút lệnh đó để chạy thủ tục.

- Bấm nút đó lần 2 để kiểm tra.

Ý nghĩa của bài tập này: Tìm ra lỗi code của mình và bẫy lỗi như thế nào.

Các bạn có thể vận dụng kiến thức từ trong topic này để thực hiện, không cần phải tìm xa hơn trong diễn đàn này đâu!

Dĩ nhiên bẫy lỗi ta phải dùng hàm IF nhiều rồi!

CÁC BẠN MỚI HỌC VBA HÃY TỰ THỰC HÀNH, TỰ MÀY MÒ ĐỂ CÓ THÊM KINH NGHIỆM CHO CHÍNH BẢN THÂN, ĐỪNG HỎI NHỮNG NGƯỜI ĐÃ BIẾT NHÉ VÌ ĐÓ CHÍNH LÀ KIẾN THỨC CỦA BẢN THÂN MÌNH.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Em nghĩ là khi xây dựng topic này thì chủ topic đã có ý đồ về hệ thống bài học cho người mới bắt đầu. Từ đơn giản đến phức tạp và chỉ nên 1 thầy ra đề. Rồi các thành viên muốn học sẽ tham gia giải bài tập theo cách của mình, kể cả cách theo ngôn ngữ ADO của Anh chàng ngốc. Vì mỗi người có phương pháp giải quyết vấn đề khác nhau. Kể cả ngôn ngữ ADO cũng là phương pháp hay.
Việc anh Nghĩa đưa ra câu hỏi để thách đố với Anh chàng Ngốc vậy e nghĩ là chưa phù hợp. Một thành viên mới thì hãy cứ để bạn ấy học theo cách của bạn ấy. Kiến thức mênh mông người mạnh mặt này hay yếu mặt khác đều phải tự bồi đắp kiến thức. Chẳng ai nói tài được tất cả các vấn đề cả. Rất nhiều thành viên dù là mới nhưng rất giỏi hoặc kiến thức rộng nhưng chưa thể hiện...
A Nghĩa là người vững về kiến thức thì có thể hỗ trợ topic này bằng cách góp ý cho "học sinh" về các lỗi mà họ mắc phải khi giải bài tập.
 
Lần chỉnh sửa cuối:
Upvote 0
Em nghĩ là khi xây dựng topic này thì chủ topic đã có ý đồ về hệ thống bài học cho người mới bắt đầu. Từ đơn giản đến phức tạp và chỉ nên 1 thầy ra đề. Rồi các thành viên muốn học sẽ tham gia giải bài tập theo cách của mình, kể cả cách theo ngôn ngữ ADO của Anh chàng ngốc. Vì mỗi người có phương pháp giải quyết vấn đề khác nhau. Kể cả ngôn ngữ ADO cũng là phương pháp hay.
Việc anh Nghĩa đưa ra câu hỏi để thách đố như vậy e nghĩ là chưa phù hợp. Một thành viên mới thì hãy cứ để bạn ấy học theo cách của bạn ấy.

Học thì cũng có chính khóa, phụ khóa, trong một lớp học chúng ta cũng tự chia nhóm ra để học, rồi học thêm ở các nơi khác nữa.

Đây không phải là một bài quá khó, nó còn dễ hơn rất nhiều so với bác Sa_DQ ra bài tập nữa. Và khẳng định với bạn đây không phải là "câu đố", qua theo dõi các bài mà các bạn đã thực hành trong topic này thì các bạn đã thành thạo việc End(xlup), Resize, Offset cả rồi nên đầu tư một tí để có thêm kinh nghiệm xử lý trên Range là một hành trang cần thiết cho việc bẫy lỗi cơ bản nhất (không muốn nói là sơ đẳng nhất) để các bạn tiếp tục bước đi một cách vững chắc trong việc học này.

Bạn có thể không trả lời bài này, nhưng bạn cứ thử nếu bạn thích.

Trân trọng.
 
Upvote 0
Tôi nghĩ không sao cả. Bạn "anh chàng ngốc" cứ giải, không giải được, ta nói không giải được, sợ gỉ ? ta đang học mà. Còn bạn Nghĩa ra đề vì thấy bạn "anh cháng ngốc" khá về ADo nên ra đề riêng thôi, cũng là để học. Mình chả biết Ado, không mình cũng thử .
 
Upvote 0
Tôi nghĩ không sao cả. Bạn "anh chàng ngốc" cứ giải, không giải được, ta nói không giải được, sợ gỉ ? ta đang học mà. Còn bạn Nghĩa ra đề vì thấy bạn "anh cháng ngốc" khá về ADo nên ra đề riêng thôi, cũng là để học. Mình chả biết Ado, không mình cũng thử .

Oh không, đây là dạng căn bản nhất, bạn thử hỏi bác ChanhTQ@ xem có phải vậy không? Còn việc thêm phần P/s là sau này thôi, không có gì là khó, gợi ý cho các bạn nè:

Mã:
Sub test()
    Range("VungDaXacDinh").ClearContents
End Sub

Quan trọng là bạn phải tìm cho được Vùng đã xác định như thế nào thôi. Quá đơn giản mà.
 
Upvote 0
Giả sử tôi có Sheet1 và một cơ sở dữ liệu, bắt đầu từ dòng 4 là dòng tiêu đề, tôi muốn các bạn xóa dữ liệu (ClearContents) từ dòng 5 trở đi, không xóa tiêu đề nha các bạn.

Bài này chắc chắn là 1 phần nhỏ trong 1 bài toán lớn nào đó
Đương nhiên các bạn có nhiều cách làm, nhưng nếu là tôi làm thì chả cần xlUp, xlDown gì ráo --> Cứ đơn giản là Range("A5:H60000").ClearContents cho khỏe thân
Đã "quét dọn" mà cũng tiết kiệm nữa sao?
Có thể ai đó sẽ nói rằng "vì sợ xóa nhầm "cái thứ gì đó" phía dưới dòng cuối cùng có dữ liệu của cột A" ---> Tôi sẽ trả lời rằng: "Dữ liệu kiểu đó là không thể chấp nhận!"
 
Upvote 0
Bài này chắc chắn là 1 phần nhỏ trong 1 bài toán lớn nào đó
Đương nhiên các bạn có nhiều cách làm, nhưng nếu là tôi làm thì chả cần xlUp, xlDown gì ráo --> Cứ đơn giản là Range("A5:H60000").ClearContents cho khỏe thân
Đã "quét dọn" mà cũng tiết kiệm nữa sao?
Có thể ai đó sẽ nói rằng "vì sợ xóa nhầm "cái thứ gì đó" phía dưới dòng cuối cùng có dữ liệu của cột A" ---> Tôi sẽ trả lời rằng: "Dữ liệu kiểu đó là không thể chấp nhận!"

Thầy ơi, đây chẳng là gì cả, đơn giản là một bài thực hành, giống như Bài làm thêm trong việc học mà thôi. Dùng xóa để đơn giản chứ biết đâu không phải là xóa mà là một thứ gì khác, copy paste hay chọn vùng đặt name chẳng hạn, sẽ làm sao xác định cho chính xác vùng và địa chỉ thật sự đây khi vùng dữ liệu chỉ là vùng rỗng chẳng có dữ liệu nào cả ngoài cái tiêu đề cột?

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

Với tất cả các bạn mới "vào nghề":

Nếu các bạn sau khi tự thực hành và đã gặp trường hợp như thế nào, bị lỗi ở đâu trền phần bài tập của mình, các bạn đưa cái lỗi ấy lên và chúng ta vừa gỡ rối để cùng nhau học tập nhé!
 
Lần chỉnh sửa cuối:
Upvote 0
Thầy ơi, đây chẳng là gì cả, đơn giản là một bài thực hành, giống như Bài làm thêm trong việc học mà thôi. Dùng xóa để đơn giản chứ biết đâu không phải là xóa mà là một thứ gì khác, copy paste chẳng hạn, sẽ làm sao xác định cho chính xác vùng và địa chỉ thật sự đây?

Đương nhiên tôi thừa hiểu "ý đồ" của Nghĩa trong bài toán này... nhưng dù sao thì Nghĩa cũng phải đưa bài toán cho thực tế hơn một chút ---> Ai rảnh đâu mà nghĩ cái chuyện không thực tế kia chứ (đã quét dọn còn định vị cóc khô gì cho mệt)
Ẹc... Ẹc...
 
Upvote 0
Đương nhiên tôi thừa hiểu "ý đồ" của Nghĩa trong bài toán này... nhưng dù sao thì Nghĩa cũng phải đưa bài toán cho thực tế hơn một chút ---> Ai rảnh đâu mà nghĩ cái chuyện không thực tế kia chứ (đã quét dọn còn định vị cóc khô gì cho mệt)
Ẹc... Ẹc...

Em giả sử thầy muốn chọn một vùng nào đó làm List cho ComboBox, vậy nếu chọn hết từ ô A5 cho đến ô A65536 để add list hay sao? Phải End(xlUp) để loại trừ dòng rỗng chứ!


Bài tập này là em lấy ý tưởng từ bài này mà ra đây:

Tiếp tục bài 8 (Hic, em chỉ kẻ vẽ khung viền được như thế này thôi)

Mã:
Sub Xuan5()
Worksheets("Sheet1").Activate
With Range([B8], [B1000].End(xlUp)).Offset(, -1).Resize(, 4)
.Borders.LineStyle = xlContinuous
 End With
With Range("B1000").End(xlUp)
 .Offset(1, 1) = "Ngay        thang          nam"
 .Offset(2) = "Nguoi Lap Bang"
 .Offset(2, 2) = "Nguoi Kiem Soat"
 End With
 End Sub

Hi Hi , cái code này bấm 2 lần sao nhỉ
---------------
Spam 1 tý, mình cũng đang học hỏi đó!
 
Lần chỉnh sửa cuối:
Upvote 0
Chắc code thế này được chứ anh Nghĩa:
PHP:
Sub DataClear()
Set sw = Worksheets("Sheet1")
Sheets("Sheet1").Activate 
irow = sw.Cells(Rows.Count, 1).End(xlUp).Row
Range(Cells(5, 1), Cells(irow, 8)).ClearContents
End Sub
 
Upvote 0
Với tất cả các bạn mới "vào nghề":

Nếu các bạn sau khi tự thực hành và đã gặp trường hợp như thế nào, bị lỗi ở đâu trền phần bài tập của mình, các bạn đưa cái lỗi ấy lên và chúng ta vừa gỡ rối để cùng nhau học tập nhé!
có câu này của sư huynh thì mọi người thảng nhiên up bài rồi hen, ko cần e ngại gì hết.

Chắc code thế này được chứ anh Nghĩa:
PHP:
Sub DataClear()
Set sw = Worksheets("Sheet1")
Sheets("Sheet1").Activate 
irow = sw.Cells(Rows.Count, 1).End(xlUp).Row
Range(Cells(5, 1), Cells(irow, 8)).ClearContents
End Sub
thì cũng dùng xlup rồi, mà ý anh Ndu thi ko xài tới xlup hay xldown

Bài này chắc chắn là 1 phần nhỏ trong 1 bài toán lớn nào đó
Đương nhiên các bạn có nhiều cách làm, nhưng nếu là tôi làm thì chả cần xlUp, xlDown gì ráo --> Cứ đơn giản làRange("A5:H60000").ClearContents cho khỏe thân
Đã "quét dọn" mà cũng tiết kiệm nữa sao?
Có thể ai đó sẽ nói rằng "vì sợ xóa nhầm "cái thứ gì đó" phía dưới dòng cuối cùng có dữ liệu của cột A" ---> Tôi sẽ trả lời rằng: "Dữ liệu kiểu đó là không thể chấp nhận !"
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Chắc code thế này được chứ anh Nghĩa:
PHP:
Sub DataClear()
Set sw = Worksheets("Sheet1")
Sheets("Sheet1").Activate 
irow = sw.Cells(Rows.Count, 1).End(xlUp).Row
Range(Cells(5, 1), Cells(irow, 8)).ClearContents
End Sub

Tốt lắm! Bạn đã chọn vùng chính xác! Mời các bạn tiếp tục giải tiếp nhé! Sau đó tôi sẽ nói nguyên do mà tôi đưa bài tập này lên đây!

thì cũng dùng xlup rồi, mà ý anh Ndu thi ko xài tới xlup hay xldown

Bài tập này là dùng End(xlUp) mai mốt còn dùng đến End(xlDown), End(xlToLeft), End(xlToRight) nữa các bạn ơi! Nếu chọn địa chỉ cứng ngắc, bất di bất dịch như vậy thì dữ liệu rỗng sẽ khủng khiếp lắm đấy!

Chú nên sửa lại tiêu đề giống như các đề bài khác đã có trong topic; đánh số tiếp tục;

(/iệc này sẽ tiện cho0 mọi người theo dõi, một khi được tác gia topic tóm lược vô bài đầu của topic.

(Bài này sẽ được xóa, 1 khi Nghĩa nhấn nút 'Thanks' & thực hiện những iêu cầu nhỏ nhẹ này!) --=0

Coi như bài tập làm thêm được không ạ, Chính vẫn là bác SA, mọi bài tập căn bản đến nâng cao đều do Bác SA ra đề. Lâu lâu cũng có vài bài tập ngoại khóa để kiểm tra mức độ hiểu bài của các bạn mới tham gia chứ nhỉ?
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Một xu hướng khác nè:

Xài fương thức không đụng hàng: CurentRegion.Ofset(1). . . .
 
Upvote 0
Có vẻ các bạn cho là khó thì tôi cũng không muốn tham gia trong topic này nữa!

Giả sử tôi có Sheet1 và một cơ sở dữ liệu, bắt đầu từ dòng 4 là dòng tiêu đề, tôi muốn các bạn xóa dữ liệu (ClearContents) từ dòng 5 trở đi, không xóa tiêu đề nha các bạn.

- Lấy cột A làm chuẩn.

- Dùng phương thức End(xlUp) để dò hàng cuối cùng của cột A rồi từ cột A các bạn tính hay xác định đến các cột khác để xóa dữ liệu.

- Sau khi hoàn tất thủ tục, gán macro xóa đó vào nút lệnh có sẳn (Xóa hàng).

- Bấm nút lệnh đó để chạy thủ tục.

- Bấm nút đó lần 2 để kiểm tra.

Ý nghĩa của bài tập này: Tìm ra lỗi code của mình và bẫy lỗi như thế nào.

Mục đích tôi:

1) Các bạn xác định được vùng cần tìm/ copy/ xóa/ tạo name/ gán mảng ... cho một vùng dữ liệu cần thiết

2) Nếu trường hợp dữ liệu không có, bạn phải biết cách để làm sao để xử lý nó.

Như bạn này:

Chắc code thế này được chứ anh Nghĩa:
PHP:
Sub DataClear()
Set sw = Worksheets("Sheet1")
Sheets("Sheet1").Activate 
irow = sw.Cells(Rows.Count, 1).End(xlUp).Row
Range(Cells(5, 1), Cells(irow, 8)).ClearContents
End Sub

Với thủ tục đó bạn đã làm rất đúng việc xác định vùng dữ liệu rồi, tôi hoan nghênh tinh thần của bạn.

Nhưng với lần thử code thứ 2 các bạn sẽ gặp một lỗi CỰC NGUY HIỂM đó là XÓA LUÔN CÁI TIÊU ĐỀ! Tôi dám chắc chắn 100% là như vậy nếu các bạn không biết bẫy lỗi!

Vậy thì thông qua cơ chế của End(xlUp) - cái này các bạn phải thử nhiều lần để thấy được việc này vì vậy tôi mới yêu cầu các bạn tự làm - thì không có dữ liệu nó sẽ lấy luôn phần cận trên của ô A5 tức là A4 và nếu không có gì cả nó sẽ chạy đến ô A1 mặc dù ta đặt mốc cho nó là A5.

Thế thì ta phải bẫy lỗi!

Thủ tục chỉ thế này thôi:

Mã:
Sub DataClear()
    Dim iRow As Long
    iRow = Sheet1.[A65536].End(xlUp).Row
    If iRow > 4 Then
        Sheet1.Range("A5:H" & iRow).ClearContents
    End If
End Sub

Với code trên các bạn tự tìm hiểu vì sao như vậy nhé!

Chào các bạn tại đây.
 
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
}}}}} Em hoàn thiện lại bài tập 8 sau khi mọi người góp ý.
Em cảm ơn ý kiến đóng góp quý báu của mọi người

Mã:
Public Sub Xuan5()
Application.ScreenUpdating = False
Dim Rng As Range, Cll As Range, Dau As Long, Cuoi As Long, I As Long, TC As Double
Dim Tem As Long, SoThang As Long, Thang As Long, Mx As Double, Tong As String, Xuan As String
With Sheets("ChiFi")
    Set Rng = .Range(.[A4], .[A65000].End(xlUp))
End With
With Sheets("sheet1")
Xuan = .[B7].Value: Tong = .[H1].Value
    With .[A8:D1000]
        .ClearContents
        .Interior.ColorIndex = 0
        .Borders.LineStyle = xlNone
    End With
Dau = DateSerial(Year(.[C4]), Month(.[C4]), 1)
Cuoi = DateSerial(Year(.[C5]), Month(.[C5]), 1)
SoThang = DateDiff("m", Dau, Cuoi) + 1
For I = 1 To SoThang
    Mx = 0
    Thang = DateSerial(Year(Dau), Month(Dau) + I - 1, 1)
    .Cells(I + 7, 1).Value = I
    .Cells(I + 7, 2).Value = Xuan & " " & Format(Thang, "mm/yyyy")
    For Each Cll In Rng
        If Cll >= .[C4] And Cll <= .[C5] Then
                Tem = DateSerial(Year(Cll), Month(Cll), 1)
            If Tem = Thang Then
                .Cells(I + 7, 3).Value = .Cells(I + 7, 3).Value + Cll.Offset(, 4).Value
                TC = TC + Cll.Offset(, 4).Value
                If Mx < Cll.Offset(, 4).Value Then
                    Mx = Cll.Offset(, 4).Value
                    .Cells(I + 7, 4).Value = Cll.Value
                End If
            End If
        End If
    Next
Next I
    With .Range("B65000").End(xlUp)
        .Offset(1, -1).Resize(, 4).Interior.ColorIndex = 6
        .Borders.LineStyle = xlNone
        .Offset(1).Value = Tong
        .Offset(1, 1).Value = TC
        .Offset(3, 1) = [H2]
        .Offset(4) = [H3]
        .Offset(4, 2) = [H4]
    End With
    .Range(.[B8], .[B8].End(xlDown)).Offset(, -1).Resize(, 4).Borders.LineStyle = xlContinuous
End With
Set Rng = Nothing
Application.ScreenUpdating = True
End Sub
 

File đính kèm

Upvote 0
Có vẻ các bạn cho là khó thì tôi cũng không muốn tham gia trong topic này nữa!

em vừa định phát ngôn thì anh BaTe đi trước rồi,
????????????????
Sao nóng tính quá vậy "em mình"?
Tôi đang nóng lòng muốn xem thêm các ví dụ của "em mình" mà.

do nhiều bạn ko xem tiêu đề tóp, đây chỉ là bài tập thực tập tất cả các hàm và lệnh của VBA cho người mới nhập, để làm quen, chứ chưa phải các bài làm thực tế sử dụng các bạn ạ.
 
Lần chỉnh sửa cuối:
Upvote 0
}}}}} Em hoàn thiện lại bài tập 8 sau khi mọi người góp ý.
Em cảm ơn ý kiến đóng góp quý báu của mọi người

Mã:
Public Sub Xuan5()
Application.ScreenUpdating = False
Dim Rng As Range, Cll As Range, Dau As Long, Cuoi As Long, I As Long, TC As Double
Dim Tem As Long, SoThang As Long, Thang As Long, Mx As Double, Tong As String, Xuan As String
With Sheets("ChiFi")
    Set Rng = .Range(.[A4], .[A65000].End(xlUp))
End With
With Sheets("sheet1")
Xuan = .[B7].Value: Tong = .[H1].Value
    With .[A8:D1000]
        .ClearContents
        .Interior.ColorIndex = 0
        .Borders.LineStyle = xlNone
    End With
Dau = DateSerial(Year(.[C4]), Month(.[C4]), 1)
Cuoi = DateSerial(Year(.[C5]), Month(.[C5]), 1)
SoThang = DateDiff("m", Dau, Cuoi) + 1
For I = 1 To SoThang
    Mx = 0
    Thang = DateSerial(Year(Dau), Month(Dau) + I - 1, 1)
    .Cells(I + 7, 1).Value = I
    .Cells(I + 7, 2).Value = Xuan & " " & Format(Thang, "mm/yyyy")
    For Each Cll In Rng
        If Cll >= .[C4] And Cll <= .[C5] Then
                Tem = DateSerial(Year(Cll), Month(Cll), 1)
            If Tem = Thang Then
                .Cells(I + 7, 3).Value = .Cells(I + 7, 3).Value + Cll.Offset(, 4).Value
                TC = TC + Cll.Offset(, 4).Value
                If Mx < Cll.Offset(, 4).Value Then
                    Mx = Cll.Offset(, 4).Value
                    .Cells(I + 7, 4).Value = Cll.Value
                End If
            End If
        End If
    Next
Next I
    With .Range("B65000").End(xlUp)
        .Offset(1, -1).Resize(, 4).Interior.ColorIndex = 6
        [COLOR=#ff0000].Borders.LineStyle = xlNone[/COLOR]
        .Offset(1).Value = Tong
        .Offset(1, 1).Value = TC
        .Offset(3, 1) = [H2]
        .Offset(4) = [H3]
        .Offset(4, 2) = [H4]
    End With
    .Range(.[B8], .[B8].End(xlDown)).Offset(, -1).Resize(, 4).Borders.LineStyle = xlContinuous
End With
Set Rng = Nothing
Application.ScreenUpdating = True
End Sub
Cái dòng màu đỏ hình như bị "dờ ư dư huyền ... thừa" (Kiểu quýnh vần của concogia).
Mã:
With .Range("B65000").End(xlUp)
        .Offset(1, -1).Resize(, 4).Interior.ColorIndex = 6
        [COLOR=#ff0000][B].Borders.LineStyle = xlNone[/B][/COLOR]
        .Offset(1).Value = Tong
        .Offset(1, 1).Value = TC
        .Offset(3, 1) = [H2]
        .Offset(4) = [H3]
        .Offset(4, 2) = [H4]
    End With
Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Hic. Rứa là bài 8 của em chưa phải là "hoàn thiện". Thôi, em cố gắng ở bài sau vậy ạ. Lên bảng giải bài tập kiểu này chắc em toàn mang "trứng vịt lộn" hay "trứng ngỗng" về nhà luộc ăn. 0 điểm tròn trĩnh cho bài tập. Hic hic....

Mờ mắt chân run thức đêm mần...với code
Viết code xong hoảng hốt thấy...bị thừa

.............
 
Upvote 0
Hic. Rứa là bài 8 của em chưa phải là "hoàn thiện". Thôi, em cố gắng ở bài sau vậy ạ. Lên bảng giải bài tập kiểu này chắc em toàn mang "trứng vịt lộn" hay "trứng ngỗng" về nhà luộc ăn. 0 điểm tròn trĩnh cho bài tập. Hic hic....

Mờ mắt chân run thức đêm mần...với code
Viết code xong hoảng hốt thấy...bị thừa

.............
Dư nhưng không ảnh hưởng đến "hòa bình thế giới", nó vẫn chạy mà.
Chỉ là nhìn nó đứng đó mà chẳng ai ngó ngàng đến hơi "kỳ kỳ" vậy thôi.
(Bộ vừa viết code vừa đi sao mà chân run?
Nếu ngồi tại chỗ phải là "ông mê" chớ!)
 
Upvote 0
Dư nhưng không ảnh hưởng đến "hòa bình thế giới", nó vẫn chạy mà.
Chỉ là nhìn nó đứng đó mà chẳng ai ngó ngàng đến hơi "kỳ kỳ" vậy thôi.
(Bộ vừa viết code vừa đi sao mà chân run?
Nếu ngồi tại chỗ phải là "ông mê" chớ!)

Hic, từ ngày em học VBA quả thật là đam mê. Có hôm quên cả ăn nên đói và thành "mắt mờ chân run" là đó ạ. hihi.

Thôi đợi bài tập 9 em sẽ cố gắng làm tốt hơn.

 
Upvote 0
Học kiểu này mình thấy hay. Trò thức đêm, thày cũng thức đêm. Trò dậy sớm thày cũng dậy sớm. Đúng kiểu học mẫu giáo, chỉ khác thày không phải ru à ơi trong lúc ngủ gật thôi. Và hay nhất là không bị thầy gõ thước vào cái đầu gỗ .
 
Upvote 0
Tôi thấy bài Trọng Nghĩa đưa ra là 1 bài tập rất thực tế. Xác định vùng xóa bên dưới tiêu đề bằng End(xlUp) mà không bẫy lỗi, thì khi không có dữ liệu sẽ xóa cả dòng tiêu đề, có khi xóa luôn dòng bên trên dòng tiêu đề luôn ấy chứ.

Nghĩa cũng thì dụ bằng code của saodoingoi, và thí dụ này chính là cái mà Nghĩa muốn nói:

Sub DataClear()
Set sw = Worksheets("Sheet1")
Sheets("Sheet1").Activate
irow
= sw.Cells(Rows.Count, 1).End(xlUp).Row
Range
(Cells(5, 1), Cells(irow, 8)).ClearContents
End Sub

Chạy lần 1, irow = 100, vùng xóa là A5:H100
Chạy lần 2, irow = 4, vùng xóa là A5:H4 hoặc viết xuôi lại là A4:H5, xóa tiêu đề dòng 4.

Giả sử tiêu đề A4 không có, (Có thể là STT nhưng bỏ trống), thế thì irow = 1 hoặc 2, 3, vùng xóa sẽ là A5:H1 hoặc A5:H2 hoặc A5:H3, ...

Chạy lần 3, A4 đã bị xóa trong lần 2, sẽ xóa tiếp lên trên dòng 4.
 
Lần chỉnh sửa cuối:
Upvote 0
Thí dụ bài fill công thức cho nhiều vùng bên dưới tiêu đề, mỗi vùng cách nhau 1 dòng có tiêu đề con,
http://www.giaiphapexcel.com/forum/...iúp-đỡ-về-macro-fill-down&p=456351#post456351

PHP:
Sub FillFormula()
Dim EndR As Long, BeginR As Long
    EndR = Sheet5.[A65000].End(xlUp).Row
    BeginR = Sheet5.Cells(EndR, 1).End(xlUp).Row
Do
    Sheet5.Cells(BeginR, 3).Resize(1, 11).AutoFill _
    Destination:=Sheet5.Cells(BeginR, 3).Resize(EndR - BeginR + 1, 11)
    EndR = Sheet5.Cells(BeginR, 1).End(xlUp).Row
    BeginR = Sheet5.Cells(EndR, 1).End(xlUp).Row
    If BeginR < 6 Then Exit Do
Loop
End Sub

Nếu không có điều kiện If BeginR < 6 sẽ xảy ra 2 lỗi:

- Những dòng từ 5 đến 1 cũng bị fill từng vùng nhỏ một, (hoặc gom thành 1 vùng), mất dòng tiêu đề, thay vào đó là nội dung dòng trên của nó
- Khi đến dòng 1, code không thoát vòng lặp, chạy mòn mỏi.

Không những thế, viết code xong còn phải khuyến cáo cột A đánh số thứ tự phải đúng, không trống ô nào. Chèn dòng xong không đánh số TT là thường tình.
 
Lần chỉnh sửa cuối:
Upvote 0
Bài tập nhỏ tiếp theo: Trong cột B, từ B4 đến B65535 có thể trống hoặc chữ, hoặc số, hãy đánh số thứ tự ở cột A theo các ô có chữ trong cột B. (Đối tượng: các "em" mới học VBA).
 
Upvote 0
Bài tập nhỏ tiếp theo: Trong cột B, từ B4 đến B65535 có thể trống hoặc chữ, hoặc số, hãy đánh số thứ tự ở cột A theo các ô có chữ trong cột B. (Đối tượng: các "em" mới học VBA).
Em cũng mới học, mò mãi không biết làm thế nào. Nhờ Record macro cũng ra được cái kết quả rồi edit lại tí cho đẹp. Up lên các bạn tham khảo cho vui.

PHP:
Sub STT()
   With Range([B4], [B65536].End(3)).SpecialCells(2)
      .Offset(, -1) = 1
      .Offset(, -1).DataSeries
   End With
End Sub
 
Upvote 0
Em cũng mới học, mò mãi không biết làm thế nào. Nhờ Record macro cũng ra được cái kết quả rồi edit lại tí cho đẹp. Up lên các bạn tham khảo cho vui.

PHP:
Sub STT()
   With Range([B4], [B65536].End(3)).SpecialCells(2)
      .Offset(, -1) = 1
      .Offset(, -1).DataSeries
   End With
End Sub
Ôi Trời ơi, hay quá. Bái phục, bái phục
Nhưng:
thanhlanh
Bài tập nhỏ tiếp theo: Trong cột B, từ B4 đến B65535 có thể trống hoặc chữ, hoặc số, hãy đánh số thứ tự ở cột A theo các ô có chữ trong cột B.
Híc, híc, híc
 
Upvote 0
????????????????
Sao nóng tính quá vậy "em mình"?
Tôi đang nóng lòng muốn xem thêm các ví dụ của "em mình" mà.

Hôm qua cảm thấy nhiều người không đồng tình với mình, cũng có người cho rằng mình có ý định làm khó cho một ai đó, cũng có người nghĩ mình "sọt dưa" vào cái topic này nên cảm thấy bực bội tí.

Nhưng hôm nay, sau một giấc ngủ thì mọi việc đã quên hết rồi, chẳng bận tâm nữa, lại tiếp tục, lại vẫn là "độc thân, vui tính", chứ không thôi thành "độc thân, nóng tính" mất thôi!

Riêng với việc xóa hàng, tôi thừa nhận như Thầy NDU nói, cứ phang một phát từ trên xuống dưới là xong, không cần tủn mủn phải chọn vùng nào để xóa. Nhưng riêng với bài tập mình đưa lên đó thì mình không có lựa chọn nào khác phải dùng đến việc CLEARCONTENTS để dùng vào việc này mà không phải là COPY, không phải là SELECT hay thứ gì khác. MỤC ĐÍCH của mình khi dùng đến XÓA là để các bạn thấy được lỗi tiềm ẩn của phương thức END(xxx) như thế nào, với các hành động khác thì không cách nào các bạn nhận ra được cách hoạt động của END cả!

Cho nên tôi cố ép các bạn phải tự mình thử để thấy và rút ra kinh nghiệm là như vậy.

Tôi vẫn tiếp tục tham gia được chứ nhỉ?


Tôi không dám nói là tôi rành về cái này, nhưng bạn đừng cho rằng mình đã biết tất cả. Mà cho là bạn biết rồi sao lại hỏi tôi, có phải muốn bắt bẻ không? Ai cũng có thể biết Excel không hổ trợ ADO cho việc xóa dòng và xóa bảng, bạn hỏi tôi câu này nhằm mục đích gì? Có phải tôi là thành viên mới, chưa hiểu biết nhiều nên bạn muốn tôi gặp khó mà rút lui?


Bạn ơi, tôi nói bạn vẫn chưa hiểu hay sao ấy! Ý tôi muốn là ở môi trường nào thì chúng ta nên tuân thủ theo môi trường đó, học cũng nghiêm túc và chơi cũng nghiêm túc. Chúng ta đang học ngôn ngữ lập trình VBA cho người MỚI BẮT ĐẦU thì nói thiệt bản thân tôi cũng chỉ mới ngắm nghé ngôn ngữ ADO trong hơn 2 tháng nay thôi và 2 người chính hướng dẫn cho tôi là Hai Lúa Miền Tây và Anh Lê Văn Duyệt, ngoài hai anh này ra tôi còn tham khảo nhiều bài khác của các thành viên trên diễn đàn này. Cho nên tôi không thể vì tôi mới học ADO mà lại chuyển phần căn bản đó vào tại môi trường VBA của topic này được.
Trân trọng.
 
Lần chỉnh sửa cuối:
Upvote 0
Bài tập nhỏ tiếp theo: Trong cột B, từ B4 đến B65535 có thể trống hoặc chữ, hoặc số, hãy đánh số thứ tự ở cột A theo các ô có chữ trong cột B. (Đối tượng: các "em" mới học VBA).
Nhà em nộp bài, với điều kiện cột B trống dưới 20 hàng
Sub SoTT()
r = 4
STT = TT
trong = 0
Do While trong < 20
If Cells(r, 2) <> "" Then
Cells(r, 1) = STT
STT = STT + 1
trong = 0
Else
Cells(r, 1) = ""
trong = trong + 1
End If
r = r + 1
Loop
End Sub
Hỏng rồi, bài nhà em cũng mắc lỗi theo Quanghai rồi,đánh số TT cả số ;
 
Lần chỉnh sửa cuối:
Upvote 0
Ôi Trời ơi, hay quá. Bái phục, bái phục
Nhưng:
Híc, híc, híc
Em cũng ráng thử phát nữa xem sao, nhiều bài mau lên sao với anh em chứ.
PHP:
Sub STT2()
Dim cell
   For Each cell In Range([B4], [B65536].End(3)).SpecialCells(2)
      If Not IsNumeric(cell) Then
         cell.Offset(, -1) = Application.Max([A:A]) + 1
      End If
   Next
End Sub
 
Upvote 0
Em cũng mới học, mò mãi không biết làm thế nào. Nhờ Record macro cũng ra được cái kết quả rồi edit lại tí cho đẹp. Up lên các bạn tham khảo cho vui.

PHP:
Sub STT()
   With Range([B4], [B65536].End(3)).SpecialCells(2)
      .Offset(, -1) = 1
      .Offset(, -1).DataSeries
   End With
End Sub
Em tet thử mà code xảy ra một lỗi là nếu ô B bắt đầu có dử liệu sau đó ô tiếp theo không có dử liệu thì số thứ tự điền toàn số 1 thôi.
1.jpg
 
Upvote 0
Em cũng ráng thử phát nữa xem sao, nhiều bài mau lên sao với anh em chứ.
PHP:
Sub STT2()
Dim cell
   For Each cell In Range([B4], [B65536].End(3)).SpecialCells(2)
      If Not IsNumeric(cell) Then
         cell.Offset(, -1) = Application.Max([A:A]) + 1
      End If
   Next
End Sub

Cái này mới gọi là đúng nha, cái trước là sai đó, vì có cách khoảng trong dữ liệu tại cột B mà!
 
Upvote 0
Bài tập nhỏ tiếp theo: Trong cột B, từ B4 đến B65535 có thể trống hoặc chữ, hoặc số, hãy đánh số thứ tự ở cột A theo các ô có chữ trong cột B. (Đối tượng: các "em" mới học VBA).

Em làm bài này như sau:

Mã:
Public Sub Xuan()
Dim Rng As Range, Cll As Range, K As Long
Set Rng = Range("B4:B65536")
For Each Cll In Rng
If Cll <> "" Then
K = K + 1
Cll.Offset(0, -1).Value = K
End If
Next
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Em làm bài này như sau:

Mã:
Public Sub Xuan()
Dim Rng As Range, Cll As Range, K As Long
Set Rng = Range("B4:B65536")
For Each Cll In Rng
If Cll <> "" Then
K = K + 1
Cll.Offset(0, -1).Value = K
End If
Next
End Sub

Giỏi lắm, tôi định hướng các bạn làm theo cách này đó! Các bạn không nhất thiết phải làm hàm MAX trong đây đâu!

Nhưng bạn cần chú ý, chọn vùng phải chọn lọc chứ đừng phang kiểu này nhé: Set Rng = Range("B4:B65536")

Mã:
Sub Test()
    Dim fCell As Range, n As Long
    For Each fCell In Range([B4], [B65536].End(3))
        If fCell.Value <> "" Then
            n = n + 1
            fCell.Offset(, -1) = n
        End If
    Next
End Sub

Nhưng nhớ sau này có ứng dụng như vậy thì nhớ BẪY LỖI ở hàng đầu tiên nhé!
 
Lần chỉnh sửa cuối:
Upvote 0
Giỏi lắm, tôi định hướng các bạn làm theo cách này đó! Các bạn không nhất thiết phải làm hàm MAX trong đây đâu!

Nhưng bạn cần chú ý, chọn vùng phải chọn lọc chứ đừng phang kiểu này nhé: Set Rng = Range("B4:B65536")

Mã:
Sub Test()
    Dim fCell As Range, n As Long
    For Each fCell In Range([B4], [B65536].End(3))
        If fCell.Value <> "" Then
            n = n + 1
            fCell.Offset(, -1) = n
        End If
    Next
End Sub
Code bạn viết còn gặp 1 vấn đề là chạy code lần 1, khi xóa trống 1 vài cell nào đó ở cột B, chạy lại code, stt sẽ không đúng
 
Upvote 0
Thêm code nữa, cái nào trúng thì trúng. Đánh STT mà dùng For Each.. thì hơi xa xỉ hén
PHP:
Sub STT3()
With Range([B4], [B65536].End(3)).Offset(, -1)
   .Formula = "=IF(TYPE(B4)>1,MAX($A$3:A3)+1,"""")"
   .Value = .Value
End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Code bạn viết còn gặp 1 vấn đề là chạy code lần 1, khi xóa trống 1 vài cell nào đó ở cột B, chạy lại code, stt sẽ không đúng

Nếu xóa 1 cell tại cột B, cần phải xóa cột STT sau đó chạy lại code, kết quả vẫn đúng bạn ạ. Cảm ơn sự góp ý của bạn, cần thêm dòng lệnh để code chạy "ngon lành" hơn chút nữa. Hic hic.
 
Lần chỉnh sửa cuối:
Upvote 0
Thêm code nữa, cái nào trúng thì trúng. Đánh STT mà dùng For Each.. thì hơi xa xỉ hén
PHP:
Sub STT3()
With Range([B4], [B65536].End(3)).Offset(, -1)
   .Formula = "=IF(TYPE(B4)>1,MAX($A$3:A3)+1,"""")"
   .Value = .Value
End With
End Sub
HI HI thêm một cách theo code của Quang Hải:
PHP:
Sub STT()
With Range([B4], [B65536].End(3)).Offset(, -1)  
 .Formula = "=IF(TYPE(B4)>1,SUBTOTAL(3,$B$4:B4),"""")"  
 .Value = .Value
End With
End Sub
 
Upvote 0
Code bạn viết còn gặp 1 vấn đề là chạy code lần 1, khi xóa trống 1 vài cell nào đó ở cột B, chạy lại code, stt sẽ không đúng

Không hề sai! Bạn nói hoàn toàn đúng, ngoài vấn đề xóa trắng cột trước, còn phải bẫy nhiều thứ khác! Cứ mạnh dạn thảo luận đi các bạn.
 
Upvote 0
Em sửa lại code như sau: Thêm Range("A4:A65536").ClearContents. Mỗi lần chạy code sẽ xóa cột STT trước rồi dựa theo cột B gán lại STT mới

Mã:
Public Sub Xuan()
Dim Rng As Range, Cll As Range, K As Long
Set Rng = Range("B4:B65536")
Range("A4:A65536").ClearContents
For Each Cll In Rng
If Cll <> "" Then
K = K + 1
Cll.Offset(0, -1).Value = K
End If
Next
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Ví dụ tiếp theo :

Cho 1 dãy số nguyên từ A2 : A14. Viết code để tìm giá trị max, không dùng các hàm có sẵn trong excel.
 
Upvote 0
Nhưng em cũng mày mò sửa lại code như sau: Thêm Range("A4:A65536").ClearContents. Mỗi lần chạy code sẽ xóa cột STT trước rồi dựa theo cột B gán lại STT mới

Mã:
Public Sub Xuan()
Dim Rng As Range, Cll As Range, K As Long
Set Rng = Range("B4:B65536")
Range("A4:A65536").ClearContents
For Each Cll In Rng
If Cll <> "" Then
K = K + 1
Cll.Offset(0, -1).Value = K
End If
Next
End Sub
Sửa rồi mà không thay luôn

Set Rng = Range("B4:B65536")
Range("A4:A65536").ClearContents


Thành
Set Rng = Range("B4:B" & [B65536].End(3).Row)
Range("A4:A" & [A65536].End(3).Row).ClearContents
 
Upvote 0
Sửa rồi mà không thay luôn

Set Rng = Range("B4:B65536")
Range("A4:A65536").ClearContents


Thành
Set Rng = Range("B4:B" & [B65536].End(3).Row)
Range("A4:A" & [A65536].End(3).Row).ClearContents

Mình vẫn làm theo cách hiểu của mình trước đã, mình cần nắm vững cấu trúc ban đầu của các câu lệnh. Những góp ý của mọi người mình copy thành tài liệu chỉnh sửa bài tập riêng và nghiên cứu.
Với người mới học như mình, cần "nhai kỹ no lâu" với kiến thức ban đầu.
 
Lần chỉnh sửa cuối:
Upvote 0
Tip: Các khái niệm về Cell, Range, sheet...

Để cho các bạn mới tiếp cận mau chóng vấn đề tên gọi của các vấn đề liên quan đến sheet tôi khái quát một số mục như sau:

1) Sheet:

Tại một sheet mà chúng ta thấy, ngay chổ sheet tab là tên của sheet mà ta gọi là Sheet Name, nhưng với môi trường VBA nó có thêm một cái tên nữa ta gọi nó là Sheet Code (giống như ta có tên và một biệt danh vậy).

attachment.php


Vậy thì khi ta chọn sheet đó ta có thể dùng các cấu trúc sau:

Worksheets ("TenSheet").Select
Sheets("TenSheet").Select
Sheet1.Select

Như vậy đều đúng cả các bạn nhé! 2 mục trên là gọi tên <Sheet>.Name và mục đỏ gọi tên <Sheet>.CodeName các bạn nhé!

2) Range:

Với ô A1, thông thường ta viết Range("A1"), nhưng một cách khác ngắn gọn hơn ta viết [A1]

Nhưng theo tôi, khuyến khích các bạn dùng kiểu Range("A1") này hơn, bởi vì sau khi đặt dấu chấm (.) thì các List Constants sẽ được show ra để mình chọn lựa các thuộc tính, phương thức ... của nó.

3) Cells:

Ô A1 để gọi nó ta cũng có thể viết như Range, ngoài ra ta cũng còn viết theo cách khác đó là

Cells(1,1) với phương thức Cells(row,column) ta có thể điều chỉnh theo số hàng và cột để tìm địa chỉ tại ô đó.

Một số vấn đề liên quan như vậy, tôi mong các bạn hỏi thêm về các vấn đề liên quan đến mọi lĩnh vực trên sheet.
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    39.9 KB · Đọc: 87
Upvote 0
Sửa rồi mà không thay luôn

Set Rng = Range("B4:B65536")
Range("A4:A65536").ClearContents


Thành
Set Rng = Range("B4:B" & [B65536].End(3).Row)
Range("A4:A" & [A65536].End(3).Row).ClearContents

Trưa nay không ăn cơm luôn. Đã nghiên cứu sửa bài tập thì thêm luôn bẫy lỗi cho "máu":
Đói quá, nên ăn VBA luôn cho đỡ đói.

Mã:
Public Sub Xuan()
Dim Rng As Range, Cll As Range, K As Long, Rs As Long
Rs = Range("B65536").End(xlUp).Row
If Rs > 3 Then
Set Rng = Range("B4:B" & Rs)
Rng.Offset(, -1).ClearContents
For Each Cll In Rng
If Cll <> "" Then
K = K + 1
Cll.Offset(0, -1).Value = K
End If
Next
Set Rng = Nothing
End If
End Sub
 
Upvote 0
Thêm code nữa, cái nào trúng thì trúng. Đánh STT mà dùng For Each.. thì hơi xa xỉ hén
PHP:
Sub STT3()
With Range([B4], [B65536].End(3)).Offset(, -1)
   .Formula = "=IF(TYPE(B4)>1,MAX($A$3:A3)+1,"""")"
   .Value = .Value
End With
End Sub

Cũng gần đúng ý mình, nhưng giả sử trong cột B có chứa các ô "'" hoặc " ", hoặc các ô số nhưng định dạng Text thì ... tèo!
Rất nguy hiểm khi lại dùng STT đó cho việc khác, ví dụ dùng cho hàm Vlookup.
Mà Quang Hải đâu phải người mới học VBA nhỉ? nhưng kệ coi như anh em mình bàn luận cho em út nó học, còn các cao thủ thì giám sát lại mình.
-----------------
Dùng vòng lặp không chỉ xa xỉ mà rất chậm, phải không?
 
Lần chỉnh sửa cuối:
Upvote 0
Cũng gần đúng ý mình, nhưng giả sử trong cột B có chứa các ô "'" hoặc " ", hoặc các ô số nhưng định dạng Text thì ... tèo!
Rất nguy hiểm khi lại dùng STT đó cho việc khác, ví dụ dùng cho hàm Vlookup.
Mà Quang Hải đâu phải người mới học VBA nhỉ? nhưng kệ coi như anh em mình bàn luận cho em út nó học, còn các cao thủ thì giám sát lại mình.
-----------------
Dùng vòng lặp không chỉ xa xỉ mà rất chậm, phải không?
Nếu code ra kết quả sai thì xử tiếp. Sợ nhất là hỏng có dữ liệu rồi cứ đoán già đoán non rồi mần ẩu vì thất nghiệp.
 
Upvote 0
Bài tập ngoại khóa 2: Copy dữ liệu, đánh số thứ tự

Tiếp bài đánh số thứ tự của ThanhLanh, tôi đưa một bài căn bản về copy dữ liệu:

Có 3 sheet trong 1 file, sheet đầu có 2 bảng: BẢNG 1, BẢNG 2, 2 sheet tiếp theo là BẢNG 3 và BẢNG 4

Yêu cầu: COPY CÁC BẢNG QUA BẢNG 1:

1) Copy BẢNG 2 và BẢNG 4 tất cả nội dung, kể cả định dạng

2) Copy BẢNG 3 chỉ lấy giá trị (paste special value)

3) Đánh số thứ tự tại BẢNG 1 những mục đã copy.

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

MỜI CÁC BẠN THAM GIA.
 

File đính kèm

Upvote 0
Tôi thấy Code của XuanNguyen vẫn chưa đúng đề, vì đánh sô TT cả chữ số . Các bạn thử text lại, hay mình sai chỗ nào nhỉ ?
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Tiếp bài đánh số thứ tự của ThanhLanh, tôi đưa một bài căn bản về copy dữ liệu:

Có 3 sheet trong 1 file, sheet đầu có 2 bảng: BẢNG 1, BẢNG 2, 2 sheet tiếp theo là BẢNG 3 và BẢNG 4

Yêu cầu: COPY CÁC BẢNG QUA BẢNG 1:

1) Copy BẢNG 2 và BẢNG 4 tất cả nội dung, kể cả định dạng

2) Copy BẢNG 3 chỉ lấy giá trị (paste special value)

3) Đánh số thứ tự tại BẢNG 1 những mục đã copy.

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

MỜI CÁC BẠN THAM GIA.
Em đưa bài lên code hơi dài dòng, nhờ các anh chị góp ý thêm
PHP:
Sub paste1()
'PASTE VAO BANG 1
Dim iRow As Long
Dim wS As Worksheets
Set sw = Worksheets("HOANG")
Sheets("HOANG").Activate
iRow = sw.Cells(Rows.Count, 2).End(xlUp).Offset(1, 0).Row          
 sw.Cells(iRow, 2).Select        
   ActiveSheet.Paste        
   Application.CutCopyMode = False
End Sub
------------------------
Sub paste2()'
PASTE VAO BANG 1
Dim iRow As Long
Dim wS As Worksheets
Set sw = Worksheets("HOANG")
Sheets("HOANG").Activate
iRow = sw.Cells(Rows.Count, 2).End(xlUp).Offset(1, 0).Row   
        sw.Cells(iRow, 2).PasteSpecial 3     
      Application.CutCopyMode = False
End Sub
----------------------------------------------
Sub copy()
Dim iRow As Long
Dim wS As Worksheets
'Y THU NHAT
'COPY SO LIEU BANG 2
Set sw = Worksheets("HOANG")
 Sheets("HOANG").Activate
 iRow = sw.Cells(Rows.Count, 9).End(xlUp).Row
 Range(Cells(3, 9), Cells(iRow, 14)).copy
'PASTE VAO BANG 1
paste1
'COPY SO LIEU BANG 4
Set sw = Worksheets("NGHIA")
 Sheets("NGHIA").Activate 
iRow = sw.Cells(Rows.Count, 1).End(xlUp).Row
 Range(Cells(3, 1), Cells(iRow, 6)).copy
 'PASTE VAO BANG 1
paste1
' Y THU HAI
'COPY SO LIEU BANG 3
Set sw = Worksheets("TRONG") 
Sheets("TRONG").Activate
 iRow = sw.Cells(Rows.Count, 1).End(xlUp).Row 
Range(Cells(3, 1), Cells(iRow, 6)).copy
'PASTE VAO BANG 1
paste2
'Y THU 3
With Range([B3], [B65536].End(3)).SpecialCells(2)     
 .Offset(, -1) = 1      
.Offset(, -1).DataSeries   
End With
End Sub
 

File đính kèm

Upvote 0
Em đưa bài lên code hơi dài dòng, nhờ các anh chị góp ý thêm

Bạn thử làm gọn hơn trong một Sub xem sao! Bài bạn cũng rất kỳ công đó!

Chắc mình không theo được nữa rồi, ra "chầu rìa" thôi .

Bạn đã nghe hoặc đã từng hát bài "Tôi ơi đừng tuyệt vọng" chưa nhỉ! Cố lên bạn nhé!
 
Upvote 0
Bạn thử làm gọn hơn trong một Sub xem sao! Bài bạn cũng rất kỳ công đó!



Bạn đã nghe hoặc đã từng hát bài "Tôi ơi đừng tuyệt vọng" chưa nhỉ! Cố lên bạn nhé!
Cám ơn bạn!
Mình sẽ không ra, vẫn phải học chứ! Mình sẽ theo đến cùng, nhưng mình mới "va"vào VBA, kiến thức còn có hạn, nên ngồi cạnh xem và học theo các bạn thôi.
 
Upvote 0
Để cho các bạn mới tiếp cận mau chóng vấn đề tên gọi của các vấn đề liên quan đến sheet tôi khái quát một số mục như sau:

1) Sheet:

Tại một sheet mà chúng ta thấy, ngay chổ sheet tab là tên của sheet mà ta gọi là Sheet Name, nhưng với môi trường VBA nó có thêm một cái tên nữa ta gọi nó là Sheet Code (giống như ta có tên và một biệt danh vậy).

attachment.php


Vậy thì khi ta chọn sheet đó ta có thể dùng các cấu trúc sau:

Worksheets ("TenSheet").Select
Sheets("TenSheet").Select
Sheet1.Select

Như vậy đều đúng cả các bạn nhé! 2 mục trên là gọi tên <Sheet>.Name và mục đỏ gọi tên <Sheet>.CodeName các bạn nhé!

2) Range:

Với ô A1, thông thường ta viết Range("A1"), nhưng một cách khác ngắn gọn hơn ta viết [A1]

Nhưng theo tôi, khuyến khích các bạn dùng kiểu Range("A1") này hơn, bởi vì sau khi đặt dấu chấm (.) thì các List Constants sẽ được show ra để mình chọn lựa các thuộc tính, phương thức ... của nó.

3) Cells:

Ô A1 để gọi nó ta cũng có thể viết như Range, ngoài ra ta cũng còn viết theo cách khác đó là

Cells(1,1) với phương thức Cells(row,column) ta có thể điều chỉnh theo số hàng và cột để tìm địa chỉ tại ô đó.

Một số vấn đề liên quan như vậy, tôi mong các bạn hỏi thêm về các vấn đề liên quan đến mọi lĩnh vực trên sheet.
1/ 3 cách viết này :
Worksheets ("TenSheet").Select
Sheets("TenSheet").Select
Sheet1.Select

là giống nhau nhưng để hạn chế người dùng đổi tên sheet lung tung thì người ta sẽ phải viết Sheet1.Select thay vì viết theo 2 cách kia.

2/ Câu này : Cells(1,1) với phương thức Cells(row,column) ta có thể điều chỉnh theo số hàng và cột để tìm địa chỉ tại ô đó.

Theo tôi cells(....) nói chung là 1 đối tượng không phải phương thức cells gì gì đó...
 
Lần chỉnh sửa cuối:
Upvote 0
1/ 3 cách viết này :
Worksheets ("TenSheet").Select
Sheets("TenSheet").Select
Sheet1.Select

là giống nhau nhưng để hạn chế người dùng đổi tên sheet lung tung thì người ta sẽ phải viết Sheet1.Select thay vì viết theo 2 cách kia.

2/ Câu này : Cells(1,1) với phương thức Cells(row,column) ta có thể điều chỉnh theo số hàng và cột để tìm địa chỉ tại ô đó.

Theo tôi cells(....) nói chung là 1 đối tượng không phải phương thức cells gì gì đó...

Không ai tham gia giải câu hỏi của tôi nhỉ?
Ví dụ tiếp theo :

Cho 1 dãy số nguyên từ A2 : A14. Viết code để tìm giá trị max của A1 : A14, không dùng các hàm có sẵn trong excel.


Chắc khó quá, hic hic

Vâng, cám ơn bạn đã góp ý thêm cho Sheet.Select, riêng việc ghi chưa đúng, đôi khi viết vội nên tôi cũng không chú ý câu từ. Xin cám ơn bạn đã nhắc nhở.

À chắc tôi nghĩ mọi người cho rằng bài VD của bạn hơi qua so với trình độ của họ nên chưa ai có đáp án, thôi thì tôi đưa ra lời giải luôn nha:

PHP:
Sub RangeMax()
    Dim n As Long, cel As Range
    For Each cel In Sheet1.Range("A2:A14")
        If Val(cel) > n Then n = cel
    Next
    MsgBox n
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Mình xin làm "nghĩa vụ" của người ra đề là giải đề, đúng, sai, hay, dở ... mọi người góp ý, không nhất thiết phải theo cách của mình.

Tóm tắt lại đề: Đánh số TT các ô có chữ (trừ ô có số, có rác) của cột B (bắt đầu từ B4) vào cột A

Mã:
Sub SoTT()
    Dim EndRow As Long
    With Sheets("Sheet1")
        EndRow = .Range("B65536").End(xlUp).Row
        If EndRow > 3 Then
            With .Range("A4:A" & EndRow)
                .FormulaR1C1 = "=IF(AND(LEN(TRIM(RC[1]))>0,ISERROR(RC[1]*1)),MAX(R3C:R[-1]C)+1,"""")"
                .Value = .Value
            End With
        End If
    End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Thực ra bài này XuanNguyen82 đã làm ở #159 rồi mà;

Ví dụ tiếp theo :
Cho 1 dãy số nguyên từ A2 : A14. Viết code để tìm giá trị max của A1 : A14, không dùng các hàm có sẵn trong excel.


Chỉ khác là XN82 kết xuất ra ngày có số liệu MAX, chứ không fải số liệu MAX đó mà thôi.
 
Upvote 0
Từ bài 1 đến bài tạp 8 rất hệ thống. Cùng 1 file dữ liệu từ dễ đến khó, và cũng trong file đó đưa ra các yêu cầu đề bài.
Ngay cả bài tập nhỏ của bạn manuchungtinh nếu ra đề là:
Với dữ liệu như bài tập 8 . Viết code để tìm giá trị max của cột chi phí, không dùng các hàm có sẵn trong excel. thì hay hơn. Các bạn mới cũng có thể hiểu (đã và đang hiểu từ file đó làm tiếp như thế nào). Và cũng tiện file đó để mà làm.

Ở đây mỗi người ra đề, đề người này ra chưa kịp giải đã ra đề khác cứ lộn tùng phèo cả lên.
Ví dụ như bài của bạn thanhlanh mình thấy nhiều học viên mới giải, mấy đề sau cứ ít dần.

Cảm thấy hơi lộn xộn không theo hệ thống được như ban đầu. Mình theo dõi học tập cũng cảm thấy không được hệ thống

Vài lời góp ý chân thành, mong các bạn thứ lỗi.
 
Upvote 0
Mình xin làm "nghĩa vụ" của người ra đề là giải đề, đúng, sai, hay, dở ... mọi người góp ý, không nhất thiết phải theo cách của mình.

Tóm tắt lại đề: Đánh số TT các ô có chữ (trừ ô có số, có rác) của cột B (bắt đầu từ B4) vào cột A

Mã:
Sub SoTT()
    Dim EndRow As Long
    With Sheets("Sheet1")
        EndRow = .Range("B65536").End(xlUp).Row
        If EndRow > 3 Then
            With .Range("A4:A" & EndRow)
                .FormulaR1C1 = "=IF(AND(LEN(TRIM(RC[1]))>0,ISERROR(RC[1]*1)),MAX(R3C:R[-1]C)+1,"""")"
                .Value = .Value
            End With
        End If
    End With
End Sub
Xin lỗi anh, em không biết thuật ngữ "có rác" có nghĩa là gì ạ?
 
Upvote 0
Xin lỗi anh, em không biết thuật ngữ "có rác" có nghĩa là gì ạ?

Hì, Xin lỗi vì nói tắt, ý mình nói các ô chỉ chứa ký tự không nhìn thấy: "'", hoặc " ", theo cách của các bạn ở trên thì các ô này cũng được đánh STT.
Mà tại Nghĩa không đọc bài trước, hay lại thích thọt lét mình. Ẹc ... ẹc
"Thuật ngữ" này mình đã đọc được đâu đó trên diễn đàn.
 
Upvote 0
Chỉ khác là XN82 kết xuất ra ngày có số liệu MAX, chứ không fải số liệu MAX đó mà thôi.
[/B]
Cám ơn thầy HYen, và nhà em nghĩ Bạn XuanNguyen đã giải đúng yêu cầu của đề.
Nhưng code
Sub RangeMax()
Dim n As Long, cel As Range
For Each cel In Sheet1.Range("A2:A14")
If
Val(cel) > n Then n = cel
Next
MsgBox n
End Sub
là tìm giá trị Max của bài #185, nhưng tôi text thử thấy báo lỗi.
 
Lần chỉnh sửa cuối:
Upvote 0
Vâng, cám ơn bạn đã góp ý thêm cho Sheet.Select, riêng việc ghi chưa đúng, đôi khi viết vội nên tôi cũng không chú ý câu từ. Xin cám ơn bạn đã nhắc nhở.

À chắc tôi nghĩ mọi người cho rằng bài VD của bạn hơi qua so với trình độ của họ nên chưa ai có đáp án, thôi thì tôi đưa ra lời giải luôn nha:

PHP:
Sub RangeMax()
    Dim n As Long, cel As Range
    For Each cel In Sheet1.Range("A2:A14")
        If Val(cel) > n Then n = cel
    Next
    MsgBox n
End Sub

Cảm ơn bạn, đúng là khó thật @ @.

Mới chập chững VBA mà các bác bắt người ta xắn quần lội vào cái bài #159 để tìm thì thật là khổ, khác nào bảo người ta "go die go". Haizzzzzz

Mà code này chưa ổn bạn Hoàng Trọng Nghĩa nhỉ??? Nếu vùng từ A2 đến A14 toàn số âm (<0) thì kết quả CODE cho ra bằng 0 vì bạn đang so sánh từng phần tử trong vùng từ A2 : A14 với n và n khi vào đầu thủ tục = 0 luôn lớn hơn mọi số âm mất rồi.

Max của dãy đó sẽ luôn bằng 0 nếu nó chỉ chứa những số ÂM. Code trên của bạn chỉ áp dụng được với những phần tử thuộc từ A2 : A114 mà >=0 thôi.

Ôi lại phải chập chững tiếp... hic
 
Lần chỉnh sửa cuối:
Upvote 0
Thử đưa macro ở #149 lên thớt xem sao

Nội dung của nó, sau khi tự tiện chỉnh sửa, như sau:
PHP:
Option Explicit
Public Sub Xuan5()
 Application.ScreenUpdating = False
 Dim Rng As Range, Cls As Range, Dau As Long, Cuoi As Long
 Dim Tmp As Long, SoThg As Long, Thang As Long, Mx As Double, TC As Double, I As Long
 Dim Tong As String, Xuan As String

 With Sheets("ChiFi")
2    Set Rng = .Range(.[A4], .[A65000].End(xlUp))
 End With
 With Sheets("sheet1")
5    Xuan = .[B7].Value: Tong = .[H1].Value
    With .[A8:D1000]
        .ClearContents
        .Interior.ColorIndex = 0
        .Borders.LineStyle = xlNone
    End With
11  Dau = DateSerial(Year(.[C4]), Month(.[C4]), 1)
    Cuoi = DateSerial(Year(.[C5]), Month(.[C5]), 1)
    SoThg = DateDiff("m", Dau, Cuoi) + 1
14  For I = 1 To SoThg
        Mx = 0
        Thang = DateSerial(Year(Dau), Month(Dau) + I - 1, 1)
        .Cells(I + 7, 1).Value = I
        .Cells(I + 7, 2).Value = Xuan & " " & Format(Thang, "mm/yyyy")
        For Each Cls In Rng
            If Cls >= .[C4] And Cls <= .[C5] Then
                Tmp = DateSerial(Year(Cls), Month(Cls), 1)
                If Tmp = Thang Then
                    .Cells(I + 7, 3).Value = .Cells(I + 7, 3).Value + Cls.Offset(, 4).Value
                    TC = TC + Cls.Offset(, 4).Value
                    If Mx < Cls.Offset(, 4).Value Then
                        Mx = Cls.Offset(, 4).Value
                        .Cells(I + 7, 4).Value = Cls.Value
                    End If
                End If
            End If
31        Next
    Next I
'Format Report:'
    With .Range("B65000").End(xlUp)
        .Offset(1, -1).Resize(, 4).Interior.ColorIndex = 6
        .Borders.LineStyle = xlNone:                .Offset(4) = [H3]
        .Offset(1).Value = Tong:                    .Offset(1, 1).Value = TC
        .Offset(3, 1) = [H2]:                       .Offset(4, 2) = [H4]
38    End With
    .Range(.[B8], .[B8].End(xlDown)).Offset(, -1).Resize(, 4).Borders.LineStyle = xlContinuous
 End With
 Set Rng = Nothing
 Application.ScreenUpdating = True
End Sub


Bước đầu mình có vài nhận xét như sau:

(1*) Cần đề fòng nhập ngày đầu khảo sát nhỏ hơn ngày đầu tiên có dữ liệu trong 'Chifi'
hay ngày cuối vượt ngày cuối vừa nhập dữ liệu;

Chuyện này có thể khắc fục bằng hàm MIN() & MAX() trong Excel: Tại các ô tương ứng kề fải của 2 ô chứa các ngày mút của thời hạn khảo sát ta nhập =MAX(ChiFi!A:A) & format như bạn đang thấy;
Nghĩa là làm sao người dùng ta thấy, nhưng khi in máy sẽ không thấy!

(2*) Nên đánh số trong các dòng lệnh; Chí ít fân biệt khối các dòng lệnh, như khối xử lý số liệu, khối format form,. . .

Những con số vô tri này sẽ giúp chúng ta trao đổi thông tin giữa cộng đồng VBA trong GPE.COM; Sau này các bạn còn biết thêm rằng, giúp ta trao đổi thông tin với máy thông qua hàm Erl(), một khi ta gặp bất trắc hay lỗi;

(3*) Dòng lệnh "With Sheets("sheet1")" là quá lạm dụng, nếu xét về mặt sử dụng chương trình;
Cụ thể hơn: Bình thường muốn có kỳ báo cáo nào, ta cũng sẽ nhập ngày đầu & ngày cuối; Nhập xong 2 ngày này ta cho chạy ngay macro;
Chứ không điên khùng gì đi qua 'ChiFi' hay trang nào khác & cho chạy macro.
Í mình muốn nói là trang Sheet1 đang hay fải đang được kích hoạt; Thậm chí ta nói vầy cũng đúng: Khi mở workbook này lên luôn bao giờ cũng fải có 1 trang tính nào đó được kích hoạt & trước khi cần chạy macro, thì trang kích hoạt đó là trang Sheet1 là chuyện bình thường;
(Nói vui: Chuyện này giống như bảo bà lão trước khi ra đường rằng cần bận quần dài vô!)
Vì chuyện lạm dụng này mà câu lệnh trong With này dài thêm, như

.Range(.[B8], .[B8].End(xlDown)).Offset(, -1).Resize(, 4).Borders.LineStyle = xlContinuous


(4*) Bạn xem thêm đoạn mã lệnh từ dòng 6 đến dòng 10; Bạn thử ghi macro Clear All 1 vùng báo cáo xem răng?

. . . . . .

Tạm vài í kiến như vậy, mong tác giả chỉnh chu thêm.
 
Lần chỉnh sửa cuối:
Upvote 0
(4*) Bạn xem thêm đoạn mã lệnh từ dòng 6 đến dòng 10; Bạn thử ghi macro Clear All 1 vùng báo cáo xem răng?

. . . . . .

Tạm vài í kiến như vậy, mong tác giả chỉnh chu thêm.
Thưa thầy, nhà em thấy ý(4*) từ dòng 6 đến dòng 10 bỏ hết chỉ cần để lại :
.[A8:D1000].Clear
là được, không biết đúng không ạ ?
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn thầy HYen, và nhà em nghĩ Bạn XuanNguyen đã giải đúng yêu cầu của đề.
Nhưng code
Sub RangeMax()
Dim n As Long, cel As Range
For Each cel In Sheet1.Range("A2:A14")
If
Val(cel) > n Then n = cel
Next
MsgBox n
End Sub
là tìm giá trị Max của bài #185, nhưng tôi text thử thấy báo lỗi.
Thuật toán của bai này phải là :
- Khai báo 1 biến Rng gán giá trị từ A2 : A14
- Khai báo 1 biến maxV chẳng hạn gán maxV = giá trị của ô đầu tiên trong vùng A2 : A14 (ở đây chính là A2)
- Dùng 1 vòng For duyệt từ giá trị từ dòng thứ 3 đến dòng thứ 14
- So sánh nếu giá trị từ dòng thứ 3 đến dòng 14 giá trị nào lớn hơn maxV thì gán maxV = giá trị đó
- Gọi giá trị maxV vừa tìm được qua Msgbox

Phát triển lên thì viết Function thuật toán cũng tương tự.
 
Upvote 0
Thuật toán của bai này phải là :
- Khai báo 1 biến Rng gán giá trị từ A2 : A14
- Khai báo 1 biến maxV chẳng hạn gán maxV = giá trị của ô đầu tiên trong vùng A2 : A14 (ở đây chính là A2)
- Dùng 1 vòng For duyệt từ giá trị từ dòng thứ 3 đến dòng thứ 14
- So sánh nếu giá trị từ dòng thứ 3 đến dòng 14 giá trị nào lớn hơn maxV thì gán maxV = giá trị đó
- Gọi giá trị maxV vừa tìm được qua Msgbox

Phát triển lên thì viết Function thuật toán cũng tương tự.
Thực ra về phần thuật toán, mình chưa đủ kiến thức để lĩnh hội. Nhưng mình nói về bài toán và đáp án :
Đề:Ví dụ tiếp theo
Cho 1 dãy số nguyên từ A2:A14. Viết code để tìm giá trị max của A1:A14, không dùng các hàm có sẵn trong excel.
tức là từ A2 đến A14 ta nhập một dãy số bất kỳ và không được dùng hàm có sẵn của excel để tìm số lớn nhất của dãy số, mà phải viết code(thay hàm Max) để tìm Max của dãy số này (Mình hiểu vậy, chả biết đúng không ? mung lung quá). Mình coppy đáp án dán vào module, nhưng nó không chạy.Tập tin đính kèm
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Vấn đề cải thiện tốc độ xử lí khi áp dụng vòng lặp trong #159

Như chúng ta đã nói với nhau, bài này có rất nhiều cách làm khác nhanh gọn hơn nhiều;
Nhưng với fương thức xài vòng lặp như vầy, ta có thể tìm cách cải thiện tốc độ hơn, một khi vùng mà vòng lặp fải chạy được thu hẹp ở cả 2 đầu.

Như có bài trên đã nói, cứ mỗi kỳ hay mỗi tháng số liệu, vòng lặp đang fải xuôi ngược giáp vòng từ đầu đến cuối; (Vùng đó đang được đưa vô biến Rng trong câu lệnh

Set Rng = .Range(.[A4], .[A65000].End(xlUp))

Ta có thể nhở fương thức nào đó để mỗi lần lặp, vòng này không bắt đầu từ .[A4], mà bắt đầu từ ô [Ax] nào đó chứa dòng dữ liệu đầu tiên của ngày đầu tiên cần khảo sát.

Khi đó các bạn mường tượng thời lượng giảm đáng kể, nếu ta chỉ khảo sát số luệu tuần nào đó của dữ liệu tháng cuối cùng ta vừa nhập vô CSDL.

Các bạn có nghỉ ra cách nào để làm việc này không các bạn?
 
Lần chỉnh sửa cuối:
Upvote 0

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

Back
Top Bottom