Lấy danh mục duy nhất

Liên hệ QC

ThuNghi

Hãy cho rồi sẽ nhận!
Thành viên đã mất
Tham gia
16/8/06
Bài viết
3,808
Được thích
4,449
Tôi có lấy trên webketoan hay là giaiphapexcel (quên mất rồi) có 1 thủ tục như sau:
Chọn vùng cần lấy danh mục (mã HH...) và thực hiện macro trên, nhưng hôm nay làm lại để chỉ cho bạn thì nó báo lỗi.(ở dòng tô đậm và I). Vậy các anh chị chỉ giúp cho hòan chỉnh, nếu có thể thì giải thích tại sao. Cám ơn nhiều.

Mã:
[B]Public Sub Delete_Record()[/B]
 Dim rngData As Range
 Dim i As Integer, j As Integer
 ActiveSheet.Copy Before:=ActiveSheet
 Set rngData = Selection
 For i = 1 To rngData.Rows.Count - 1
     For j = i + 1 To rngData.Rows.Count
        If rngData.Cells(j, 1) = rngData.Cells(i, 1) And rngData.Cells(j, 2) = _
                rngData.Cells(i, 2) And rngData.Cells(j, 3) = rngData.Cells(i, 3) Then
            rngData.Cells(j, 1) = "":                rngData.Cells(j, 2) = ""
            rngData.Cells(j, 3) = ""

[COLOR="Blue"]'Range(rngData.Cells(j, 1), rngData.Cells(j, 3)).Select[/COLOR]
[COLOR="blue"]'Selection.Delete Shift:=xlUp[/COLOR]
         End If
 Next j, i
[I][B] Selection.Sort Key1:=Range(Selection.Cells(1, 1).Address), Order1:=xlAscending, _
Key2:=Range(Selection.Cells(1, 2).Address), Order2:=xlAscending, _
Key3:=Range(Selection.Cells(1, 3).Address), Order3:=xlAscending, _
Header:=xlNo, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal, DataOption2:=xlSortNormal, DataOption3:=xlSortNormal[/B][/I]
[B]End Sub[/B]
 
Chỉnh sửa lần cuối bởi điều hành viên:
ThuNghi đã viết:
Public Sub Delete_Record()
Dim rngData As Range
Dim i As Integer, j As Integer
ActiveSheet.Copy Before:=ActiveSheet
Set rngData = Selection
For i = 1 To rngData.Rows.Count - 1
For j = i + 1 To rngData.Rows.Count
If rngData.Cells(j, 1) = rngData.Cells(i, 1) And rngData.Cells(j, 2) = rngData.Cells(i, 2) And rngData.Cells(j, 3) = rngData.Cells(i, 3) Then
rngData.Cells(j, 1) = ""
rngData.Cells(j, 2) = ""
rngData.Cells(j, 3) = ""

'Range(rngData.Cells(j, 1), rngData.Cells(j, 3)).Select
'Selection.Delete Shift:=xlUp
End If
Next j
Next i
Selection.Sort Key1:=Range(Selection.Cells(1, 1).Address), Order1:=xlAscending, _
Key2:=Range(Selection.Cells(1, 2).Address), Order2:=xlAscending, _
Key3:=Range(Selection.Cells(1, 3).Address), Order3:=xlAscending, _
Header:=xlNo, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal, DataOption2:=xlSortNormal, DataOption3:=xlSortNormal
End Sub
Dear ThuNghi,
-------------
Giá như bạn cho biết thêm về câu thông báo lỗi thì mọi người xác định chính xác nguyên nhân của bệnh.
Với đoạn mã trên, mình cho rằng "bệnh" phát sinh có thể do tác giả đã sử dụng Selection. Đây là một đối tượng kiểu Range "ám chỉ" bạn đang lựa chọn một vùng nào đó. "Một vùng nào đó" phụ thuộc vào yêu cầu xử lý bảng dữ liệu của tác giả. Maxcro này thực thi việc Delete_Record bởi câu lệnh:
Selection.Delete Shift:=xlUp
nhưng tạm thời nó đang bị vô hiệu mà thay vào đó là việc xoá dữ liệu thoả mãn điều kiện:
rngData.Cells(j, 1) = rngData.Cells(i, 1) And rngData.Cells(j, 2) = rngData.Cells(i, 2) And rngData.Cells(j, 3) = rngData.Cells(i, 3)
Bạn phải hiểu về cấu trúc của bảng dữ liệu (chính là Selection) cũng như các điều kiện để xử lý các dòng muốn loại bỏ.
Nếu bạn muốn sử dụng Selection mặc định là vùng dữ liệu mà con trỏ hoạt động, bạn có thể thay thế Selection bởi đối tượng theo kiểu như sau:
Dim myRange As Range
Set myRange = ActiveCell.CurrentRegion
Việc lấy ra một danh sách duy nhất bạn có thể thực hiện đơn giản hơn bằng phương thức AdvandcedFilter:
expression.AdvancedFilter(Action, CriteriaRange, CopyToRange, Unique)
với đối số Unique là TRUE.:bb:
 
Lần chỉnh sửa cuối:
Upvote 0
Xem lại Sub Dele Record

Nhờ anh Cường và các anh xem lại sub Delete Record sau hộ:
Cột A là cột cần lấy danh mục duy nhất
 
Lần chỉnh sửa cuối:
Upvote 0
Dear ThuNghi,
--------------
Đúng như dự đoán, dụng ý của tác giả là:
nvson đã viết:
Đoạn Macro này trước khi chạy đòi hỏi bạn phải chọn vùng chọn ít nhất 3 cột, còn hàng thì tuỳ ý.
Đó chính là đối tượng Selection trong đoạn code. Một điểm mà bạn cũng cần lưu ý nữa là thủ tục này chỉ nhằm xử lý các dữ liệu trùng của 2 dòng liền kề nhau thông qua điều kiện kiểm tra:
rngData.Cells(j, 1) = rngData.Cells(i, 1) And rngData.Cells(j, 2) = rngData.Cells(i, 2) And rngData.Cells(j, 3) = rngData.Cells(i, 3)
Nếu điều kiện này đúng thì thực hiện xoá dữ liệu (Clear Contents) trong dòng thứ hai:
rngData.Cells(j, 1) = ""
rngData.Cells(j, 2) = ""
rngData.Cells(j, 3) = ""
chứ không xoá đi cả dòng (Delete Row).
Nếu bạn muốn lấy ra danh sách duy nhất, mình e rằng đoạn code trên chưa đáp ứng được (trong điều kiện các dòng trùng nhau ở cách xa nhau).
Bạn thử thực hành ghi lại một macro Advanced Filter và cải tiến chúng như sau:
- Vùng Range("A1:A12") là vùng danh sách có dữ liệu trùng nhau. (bạn lưu ý Excel sẽ lấy dòng đầu tiên làm cột tiêu đề). Bạn muốn lọc ra đủ 7 ngày trong tuần từ danh sách này.
- Thực hiện từ menu Data/ Filter/ Advanced Filter.
- Xác định vùng Copy to
- Kiểm duyệt Unique records only. Lựa chọn này cho phép trích lọc ra các item duy nhất trong danh sách mới.
- OK
Và sau đây là đoạn code mình ghi được:
Mã:
Sub UniqueRecords()
    Range("A1:A12").Select
    Range("A1:A12").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range( _
        "D1"), Unique:=True
End Sub
Thực hành với đoạn code này bằng cách khai báo một biến lưu trữ tham số địa chỉ danh sách ban đầu và một biến lưu trữ địa chỉ cột đầu tiên của danh sách mới, bạn sẽ thu được kết quả như mong muốn.
Ví dụ:
Mã:
Sub UniqueRecords(rgListRange As Range,rgCopyTo as Range)
       rgListRange.AdvancedFilter Action:=xlFilterCopy, CopyToRange:=rgCopyTo, Unique:=True
End Sub
Bạn lưu ý trên Worksheet để sử dụng được thủ tục có tham số, bạn bạn có thể truyền tham số bởi một thủ tục khác, ví dụ:
Mã:
Sub DaysofWeek()
UniqueRecords Range("A1:A12"), Range("D1")
End Sub
Chúc bạn thành công! :thumbs:
 
Upvote 0
To ThuNghi:
Marco trước là tôi viết cho bạn phochiadoi http://www.giaiphapexcel.com/forum/showthread.php?t=520

Đây là Macro đã được cải tiến cho phù hợp với yêu cầu của bạn.
PHP:
Public Sub Delete_Record()
'Macro created by Nguyen Van Son'
 If Selection.Rows.Count < 2 And Selection.Columns.Count < 2 Then
    MsgBox "Vui long chon vung du lieu truoc khi chay Macro nay!" & vbCrLf & vbCrLf _
           & "Vung du lieu co the la vung chon bat ky, khong gioi han so dong, _
           so cot ", vbInformation
    Exit Sub
 End If
 Dim rngData As Range
 Dim i As Integer, j As Integer, m As Integer, k As Integer
 Dim Cot As Integer
 Dim Record_i As Boolean
 ActiveSheet.Copy Before:=ActiveSheet
 Set rngData = Selection
 For i = 1 To rngData.Rows.Count - 1
     For j = i + 1 To rngData.Rows.Count
          Record_i = True
          For k = 1 To rngData.Columns.Count
               If rngData.Cells(j, k) <> rngData.Cells(i, k) Then
                      Record_i = False
               End If
          Next k
          If Record_i Then
                 For m = 1 To rngData.Columns.Count
                       rngData.Cells(j, m) = ""
                 Next m
          End If
 Next j, i
   Cot = InputBox("Ban dinh sap xep lai tu cot thu: ", "Nguyen Van Son", 1)
 Selection.Sort Key1:=Range(Selection.Cells(1, Cot).Address), Order1:=xlAscending,  _
          Header:=xlNo, OrderCustom:=1, MatchCase:=False,  _
          Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
End Sub

Anh Cường à.
Nếu bạn muốn lấy ra danh sách duy nhất, mình e rằng đoạn code trên chưa đáp ứng được (trong điều kiện các dòng trùng nhau ở cách xa nhau).
Macro này có thể lọc được hết trong vùng lự chọn. Không như anh nghĩ đâu. Tôi đã thử rất nhiều lần và đều chạy ổn.
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Bạn Nvson!
Cám ơn nhiều, đã thử và chạy 100 dòng rồi, chạy tốt
Nhưng mà nếu 500 records trở lên thì chậm lắm
Bạn có thể xử lý lại hộ:
1/ Copy côt cần lấy danh mục
2/ Sort cột đó
3/ Tìm từ dòng 2 nếu thấy trùng thì hủy
Có thể sẽ nhanh hơn không (tôi chỉ ứng dụng mà o biết lập trình)
Phần này ứng dụng khá nhiều
Cám ơn!
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Dear all,
--------
www.Giaiphapexcel.com hơn các diễn đàn tin học khác ở chỗ đây là diễn đàn cho giải pháp. Nghiên cứu, thảo luận cho ra vấn đề - đã đành - các thành viên biết hỗ trợ nhau để có giải pháp tối ưu nhất mới là điều quan trọng.
Nhưng đó là chuyện về Góp ý cho diễn đàn. Còn ở đây, trong chủ đề này, chúng ta cần giúp ThuNghi và các bạn hiểu về xây dựng một thủ tục loại bỏ dữ liệu trùng.
Đúng là có rất nhiều cách thức để loại bỏ dữ liệu trùng, cả bằng thủ công và lập trình. Với VBA, giải pháp tốt nhất là nhanh, gọn, dễ sử dụng lại và đặc biệt phải gần gũi với Excel. Tôi không đồng tình với giải pháp mà nvson đưa ra, nhưng đó không phải là ý kiến chính mà chỉ mong các bạn hiểu và lựa chọn giải pháp nào hiệu quả nhất.
Có lẽ không cần bàn luận nhiều, các bạn hãy so sánh hai thủ tục trong file đính kèm dưới đây rồi tự rút ra nhận xét cho mình.
 

File đính kèm

  • Filter_Unique.zip
    75.8 KB · Đọc: 212
Lần chỉnh sửa cuối:
Upvote 0
To NVSon:
Tại sao bạn không xếp theo trật tự trước rồi mới làm gì thì làm? Lõ phần nhập liệu không theo trật tự như VD thì sao?
Muốn nhanh hơn thì xài 1 số lệnh cho màn hình đừng lắc lư nữa!

(ó thể thực thi việc tìm tất cả các record giống nhau rồi xóa 1 lúc được chăng (tất nhiên đã xếp rồi!)?
ThuNghi thử PivotTable chưa; nếu chỉ lập 1 DS duy nhất ta có thể xài thứ này hay sao í; bạn thử đi nha!
 
Upvote 0
Theo mình nghĩ thì nếu chỉ dùng danh mục duy nhất mà dùng VBA thì theo như Đào Việt Cường là dùng Advance là hay nhất. Còn nếu không thì có thể dùng công thức để lọc nhưng với điều kiện là danh mục ít.
 
Upvote 0
Sub lây DM duy I

Tôi vận dụng ý kiến của các bạn và tạo một sub lấy danh mục duy nhất, theo file kèm, nhưng nhờ các bạn chỉ hộ có cách nào chọn danh mục kết xuất (sheet 2) và tự động sort lại tăng dần, vấn đề là chọn được vùng cần sort. Tôi chọn end thì nó chọn hết tòan bộ selection.

Do khi tôi kết xuất đã sort giảm dần cho thấy được ngay kết quả ở ô A1. Các bạn xem file hộ vì tôi không diễn đạt hết ý.
Xin cám ơn!
 
Lần chỉnh sửa cuối:
Upvote 0
Theo mình nghĩ thì cách của anh Cường là rất hay.
Mình sửa lại một chút cho phù hợp với công việc của bạn.
(Mong anh Cường thông cảm nhé!)
PHP:
Sub LayDM_2()
    Selection.AdvancedFilter Action:=xlFilterInPlace, Unique:=True
    [COLOR=red]ActiveCell.CurrentRegion.Select[/COLOR]
    Selection.Copy:                  Sheets.Add
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False
    Application.CutCopyMode = False
    Selection.Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _
        OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
        DataOption1:=xlSortNormal
End Sub
Ghi chú: CurrentRegion sẽ chọn toàn bộ vùng mà ô đang hoạt động
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Lại Selection!!!

Dear all,
--------
Có lẽ bài học thú vị nhất mà chúng ta có thể rút ra trong chủ đề này là Selection chứ không phải là Filter.
Đây là một thuộc tính cơ bản của đối tượng Application. Thuộc tính này có kiểu là Range, biểu hiện cho vùng lựa chọn hiện thời.
Chúng ta thường thấy thuộc tính này xuất hiện nhiều trong các thủ tục Macro. Là bởi vì sao? Theo tôi, do Selection là một Range không xác định mà Macro "không đủ thông minh" để hiểu bạn đang làm gì. Khi bạn "record" hành động lựa chọn (select) một vùng nào đó, trước hết Macro ghi nhận lại hành động này của bạn bằng phương thức Select. Tiếp theo, bạn muốn làm việc gì trên vùng lựa chọn đó, Macro lập tức khai báo từ khoá With Selection để làm việc với vùng lựa chọn.
Đó là cách viết của Macro, còn cách viết của các bạn thì sao?
Nếu bạn viết cho bạn - mình bạn hiểu - sẽ không có lỗi phát sinh. Nhưng để cho người khác sử dụng, các bạn phải thận trọng với đối tượng này.
ThuNghi đã viết:
Chọn vùng cần lấy danh mục (mã HH...) và thực hiện macro trên, nhưng hôm nay làm lại để chỉ cho bạn thì nó báo lỗi
Sẽ lại có nhiều thắc mắc đại loại như vậy chỉ vì Selection của mỗi người là khác nhau.
Theo mình, trước khi xây dựng một thủ tục VBA, cần đánh giá thủ tục đó cần bao nhiêu tham số, những tham số có kiểu là gì. Chẳng hạn, trong thủ tục của bạn, chúng ta có thể xác định được ít nhất 2 tham số cần thiết:
- Bảng dữ liệu
- Cột sắp xếp
Việc xử lý các tham số này cũng không máy khó khăn hơn việc Ctrl+R (Replace) Selection bởi tham số bảng dữ liệu của bạn.
Bước đầu tiếp cận với VBA thật không đơn giản chút nào, bạn nên tiếp cận với các bài toán đơn giản trước.
Chúc các bạn viết được thủ tục ưng ý và không có lỗi!
 
Upvote 0
Web KT
Back
Top Bottom