Chọn Range trên nhiều Sheets

Liên hệ QC

emgaingayngo

Thành viên hoạt động
Tham gia
9/2/07
Bài viết
141
Được thích
5
Tôi có 2 WorkBook : KQ2007.xls và QuyVeMot.xls va 1 Sub Copy()
Name in KQ2007.xls : "NgayCapNhat" có gía trị là date (dd/mm/yyyy)
Name in QuyVeMot.xls : "ThuHai", "ThuBa", "ThuTu", "ThuNam", "ThuSau", "ThuBay", "ChuNhat", "ThuTPHCM", "ThuChinh", "ThuPhu" , cũng có gía trị là date (dd/mm/yyyy)
Trong đó :- "ThuHai", "ThuBa", "ThuTu", "ThuNam", "ThuSau", "ThuBay", "ChuNhat" thuộc về WorkSheet!KQ( có Name là S00)
- "ThuTPHCM" thuộc về WorkSheet!TPHCM( có Name là S02)
- "ThuChinh", "ThuPhu" thuộc về WorkSheet!ChinhPhu ( có Name là S03)
Tôi muốn viết một macro làm công việc sau:
Kiểm tra "NgayCapNhat" xem có giống với "ThuHai", "ThuBa", "ThuTu", "ThuNam", "ThuSau", "ThuBay", "ChuNhat", "ThuTPHCM", "ThuChinh", "ThuPhu" không? Nếu giống thì do nothing, nếu không giống Call Sub Copy()
Mong nhận được sự giúp đỡ của các bạn. Xin cảm ơn nhiều.
 
Bạn tham khảo thôi nha:

Đoạn code này ở workbook <> 'KQ2007' & còn thiếu vài câu lệnh nữa!--=0

Mã:
Option Explicit[b]

Sub KiemTra()[/b]
[COLOR="Blue"]' Macro recorded 4/25/2007 by [B]CFC[/B]               '  Ctrl+Shift+K[/COLOR]
 Dim NgCapNhat As Date
 Dim StrC
 Dim Xh As String:              Xh = Chr(13) & Chr(10)
    On Error Resume Next
    Workbooks.Open Filename:="D:\CFC\Excel\KQ2007.xls"
    NgCapNhat = Range("Ngaycapnhat").Value
    Windows("QuiVe1.xls").Activate
    StrC = Range("ThuHai").Value & Xh & Range("ThuBa").Value & Xh & Range("ThuTu").Value
    StrC = StrC & Xh & Range("ThuNam").Value & Xh & Range("ThuSau").Value & Xh _
        & Range("ThuBay").Value & Xh & Range("ChuNhat").Value & Xh & Range("ThuHCM").Value _
        & Xh & Range("Chinh").Value & Xh & Range("Phu").Value
        
    MsgBox StrC, , NgCapNhat
    Copy[b]        
End Sub
[COLOR="blue"]   ' *    *    *    *    *[/COLOR]
Sub Copy()[/b]
  MsgBox "Sub Copy", , "Xin Chao!"[b]
End Sub[/b]
 
Upvote 0
Thank you for your macro!
Nhưng làm sao so sánh được SA_DQ ơi. Mình chưa biết cách sánh một giá trị với một chuỗi. Bạn chỉ luôn đi. Thanks much!
 
Upvote 0
Dear all,
--------
Quan sát thủ tục KiemTra() của anh SQL em thấy đúng là chưa có động tác kiểm tra.
Bài tập nêu rất rõ ràng, vấn đề ở đây là làm sao so sánh ngày cập nhật trên Workbook KQ2007.xls có khớp với một trong các Thứ trên Workbook QuyVeMot.xls hay không.
Mình chắc emgaingaytho chỉ bị vướng ở chỗ phải lấy giá trị của các Thứ như thế nào (trong bài viết trước có đề cập đến lỗi này nhưng chưa xử lý được nên mở toppic này, phải không!).
Các bước:
1. Phải lấy được chính xác các giá trị giữa 2 workbook để so sánh:
Vì cặp so sánh nằm ở 2 workbook khác nhau, do đó bạn phải chỉ ra tường minh (đầy đủ) phạm vi của Range. Mặc định nếu không chỉ ra phạm vi của Range, Excel sẽ tìm trên ActiveWorkbook, bạn có thể Workbook(i).Activate trước khi tham chiếu đến Range đó. Bằng không, dạng tường minh đầy đủ của Range sẽ là, ví dụ: (giả sử Name NgayCapNhat có tham chiếu tại ô cập nhật tren sheet CAPNHAT):
stNgayCapnhat= Workbooks("KQ2007.xls").Worksheets("CAPNHAT").Range("NgayCapnhat").Value
(Lưu ý là Workbook phải đang được mở, không nhất thiết phải Active)
Tương tự như thế, bạn phải chỉ ra đầy đủ phạm vi của Range để lấy ra các thứ trên Workbook QuyVeMot.xls (xem ở dưới)
2. So sánh Ngày cập nhật với các Thứ:
Có nhiều cách để bạn so sánh:
- So sánh lần lượt Ngày cập nhật với từng Thứ
- Sử dụng hàm tìm kiếm
Mình giới thiệu cách thứ 2 vì cách này gọn hơn:
Ý đồ của mình là sẽ sử dụng hàm InStrRev để so sánh:
Mã:
[B]InStrRev Function [/B]
Description:
Returns the position of an occurrence of one string within another, from the end of string.
Syntax:
[B]InstrRev[/B](stringcheck, stringmatch[, start[, compare]])
The InstrRev function syntax has these named arguments:
[U][B]Part        [/B][/U][U][B]   Description [/B][/U]
[B]stringcheck    [/B]Required. String expression being searched. 
[B]stringmatch    [/B]Required. String expression being searched for. 
[B]start          [/B]Optional. Numeric expression that sets the starting position for each search.
               If omitted, –1 is used, which means that the search begins at the
               last character position. If start contains. Null, an error occurs.
[B]compare    [/B]    Optional. Numeric value indicating the kind of comparison to use when evaluating 
               substrings. If omitted, a binary comparison is performed. See Settings section for values.
Với
stringmatch= stNgayCapnhat
strcheck= stCacThu 'các Thứ được xâu chuỗi lại với nhau, ví dụ:

Mã:
stCacThu = Workbooks("QuyVeMot.xls").Worksheets("KQ").Range("ThuHai").Value & ";"
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("KQ").Range("ThuBa").Value & ";"
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("KQ").Range("ThuTu").Value & ";"
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("KQ").Range("ThuNam").Value & ";"
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("KQ").Range("ThuSau").Value & ";"
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("KQ").Range("ThuBay").Value & ";"
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("KQ").Range("ChuNhat").Value & ";"
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("TPHCM").Range("ThuTPHCM").Value & ";"
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("ChinhPhu").Range("ThuChinh").Value & ";" 
stCacThu =  stCacThu & Workbooks("QuyVeMot.xls").Worksheets("ChinhPhu").Range("ThuThu").Value
Sau khi tìm được cặp so sánh, thủ tục được kiểm tra chỉ cần một dòng lệnh:
If InStrRev(stCacThu,stNgayCapnhat & ";")= 0 Then Call myCopy
(Bạn lưu ý nên đặt tên thủ tục Copy khác đi để phân biệt với phương thức của các đối tượng, ở đây tôi đặt là myCopy)
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn anh Cường đã chỉ dẫn rỏ ràng cho những người mới biết VBA như em.
Anh xem giúp đọan mã sau có giải thuật nào ngắn gọn hơn chỉ cho em.

Sub myCopy()
Dim m As Integer
S00.Activate
Range("DataCapNhatChinh").Select: Selection.Copy
S01.Activate
Range("ThuChinh").Offset(0, 1).Select: ActiveSheet.Paste
S00.Activate
Range("DataCapNhatPhu").Select: Selection.Copy
S01.Activate
Range("ThuPhu").Offset(0, 1).Select: ActiveSheet.Paste
Application.CutCopyMode = False
S00.Activate
Range("DataCapNhatChinh").Select: Selection.Copy
m = Weekday(Range("DateCapNhat").Value, vbSunday)
Select Case m
Case 1
S01.Activate
Range("ChuNhat").Offset(0, 1).Select: ActiveSheet.Paste
S00.Activate
Range("DataCapNhatPhu").Select: Selection.Copy
S01.Activate
Range("ChuNhat").Offset(21, 0).Select: ActiveSheet.Paste

Case 2
S01.Activate
Range("ThuHai").Offset(0, 1).Select: ActiveSheet.Paste
Range("ThuTPHCM").Offset(0, 1).Select: ActiveSheet.Paste
S00.Activate
Range("DataCapNhatPhu").Select: Selection.Copy
S01.Activate
Range("ThuHai").Offset(21, 0).Select: ActiveSheet.Paste

Case 3
S01.Activate
Range("ThuBa").Offset(0, 1).Select: ActiveSheet.Paste
S00.Activate
Range("DataCapNhatPhu").Select: Selection.Copy
S01.Activate
Range("ThuBa").Offset(21, 0).Select: ActiveSheet.Paste

Case 4
S01.Activate
Range("ThuTu").Offset(0, 1).Select: ActiveSheet.Paste
S00.Activate
Range("DataCapNhatPhu").Select: Selection.Copy
S01.Activate
Range("ThuTu").Offset(21, 0).Select: ActiveSheet.Paste

Case 5
S01.Activate
Range("ThuNam").Offset(0, 1).Select: ActiveSheet.Paste
S00.Activate
Range("DataCapNhatPhu").Select: Selection.Copy
S01.Activate
Range("ThuNam").Offset(21, 0).Select: ActiveSheet.Paste

Case 6
S01.Activate
Range("ThuSau").Offset(0, 1).Select: ActiveSheet.Paste
S00.Activate
Range("DataCapNhatPhu").Select: Selection.Copy
S01.Activate
Range("ThuSau").Offset(21, 0).Select: ActiveSheet.Paste
Case 7
S01.Activate
Range("ThuBay").Offset(0, 1).Select: ActiveSheet.Paste
Range("ThuTPHCM").Offset(0, 1).Select: ActiveSheet.Paste
S00.Activate
Range("DataCapNhatPhu").Select: Selection.Copy
S01.Activate
Range("ThuBay").Offset(21, 0).Select: ActiveSheet.Paste
End Select
Application.CutCopyMode = False

End Sub
 
Upvote 0
/(/)ình thấy có thể rút gọn được = cách tạo thêm 1 hay 1 vài sub nữa để nhận các tham số được truyền từ MyCopy đến 1 cách thích ứng & thực hiện các Case từ CN -> Th7 một cách thích hợp;
(ụ thể bạn (ường sẽ zúp bạn trong tw lai gần một cách hay nhất!

(húc ~ ngày nghĩ lễ &ui &ẽ!
--=0
 
Lần chỉnh sửa cuối:
Upvote 0
Zận quá! Gởi bạn mấy cái ni, tham khảo nha!

Mã:
Option Explicit
Dim s00 As Sheet1, s01 As Sheet1
[b]Sub myCopy()[/b]
 Dim m As Integer
 s00.Activate
 Range("DataCapNhatChinh").Select:          Selection.Copy
 s01.Activate
 Range("ThuChinh").Offset(0, 1).Select:     ActiveSheet.Paste
 s00.Activate
 Range("DataCapNhatPhu").Select:            Selection.Copy
 s01.Activate
 Range("ThuPhu").Offset(0, 1).Select:       ActiveSheet.Paste
 Application.CutCopyMode = False:           s00.Activate
 Range("DataCapNhatChinh").Select: Selection.Copy
 m = Weekday(Range("DateCapNhat").Value, vbSunday)

Select Case m
Case 1
    s01.Activate
    Range("ChuNhat").Offset(0, 1).Select:   ActiveSheet.Paste
    s00.Activate
    Range("DataCapNhatPhu").Select:         Selection.Copy
    s01.Activate
    Range("ChuNhat").Offset(21, 0).Select:  ActiveSheet.Paste
Case 2
    s01.Activate
    Range("ThuHai").Offset(0, 1).Select:    ActiveSheet.Paste
    Range("ThuTPHCM").Offset(0, 1).Select:  ActiveSheet.Paste
    s00.Activate
    Range("DataCapNhatPhu").Select:         Selection.Copy
    s01.Activate
    Range("ThuHai").Offset(21, 0).Select:   ActiveSheet.Paste
Case 3
    WSeLect Range("thuBa")
Case 4
    WSeLect Range("thuTu")
Case 5
    WSeLect Range("thuNam")
Case 6
    WSeLect Range("thuSau")
Case 7
    s01.Activate
    Range("ThuBay").Offset(0, 1).Select:    ActiveSheet.Paste
    Range("ThuTPHCM").Offset(0, 1).Select:  ActiveSheet.Paste
    s00.Activate
    Range("DataCapNhatPhu").Select:         Selection.Copy
    s01.Activate
    Range("ThuBay").Offset(21, 0).Select:   ActiveSheet.Paste
End Select
Application.CutCopyMode = False[b]
End Sub
[COLOR="Blue"]'        *        *               *          *[/COLOR]
Sub WSeLect(Rng As Range)[/b]
    s01.Activate
    Range(Rng).Offset(0, 1).Select:         ActiveSheet.Paste
    s00.Activate
    Range("DataCapNhatPhu").Select:         Selection.Copy
    s01.Activate
    Range(Rng).Offset(21, 0).Select:        ActiveSheet.Paste

[b]End Sub[/b]
' * * *
' * * * *

Mã:
[b]Sub ThuNghiem()[/b]
    RngName Range("NgayCapNhat")[b]
End Sub
[COLOR="Blue"]'        *        *               *          *[/COLOR]
Sub RngName(Rng As Range)[/b]
    MsgBox Rng.Value + 1
    MsgBox Rng.Name, , Rng.Address[b]
End Sub[/b]
 
Upvote 0
Dear emgaingaytho,
---------------------
Bạn nhớ lại vấn đề mà bạn gặp ở chủ đề trước (Khai báo biến và kiểm tra thứ trong tuần):
Lỗi đã viết:
run-time error '1004'
Method 'Range' of object '_Global' failed

Xuất hiện tại dòng lệnh :

Range("ThuHai").Select
là vì bạn đang cố gắng tham chiếu tới một vùng dữ liệu không tồn tại hoặc không có hiệu lực. Phải luôn luôn nhớ rằng nếu không chỉ ra phạm vi của Range tức là bạn đang có ý tham chiếu đến đối tượng đó trên Workbook hiện hành (ActiveWorkbook). Một mô hình phác thảo đơn giản để bạn hình dung khi làm việc với Range:
Mã:
[U][B]Workbook[/B][/U]
   |
   |___________[B]Worksheet[/B]
                      |
                      |__________[B]Range[/B]
                      |
                      |__________[B]Cells[/B]
 
hay: [B]Workbooks(i).Worksheets(i).Range(i)[/B]
Trở lại vấn đề chính, bạn đã cảm giác đúng khi cho rằng thủ tục chưa được ngắn gọn:

1. Có quá nhiều hành động Select và Activate:

Bạn hiểu rằng với mỗi phương thức Activate thi hành thì ngay lập tức sự kiện Worksheet_Activate() đối với Worksheet đó sẽ xảy ra, cũng tương tự cứ Select thì Worksheet_SelectionChange() lại hoạt động. Điều đó có nghĩa là sẽ có hàng loạt các hoạt động "bên trong" Workbook diễn ra một cách không cần thiết.
Để hạn chế điều này áp dụng việc tham chiếu theo mô hình trên, chẳng hạn thay vì:

S00.Activate
Range("DataCapNhatChinh").Select: Selection.Copy

bạn viết:

S00.Range("DataCapNhatChinh").Copy

(Ở đây chúng ta hiểu rằng S00 thuộc Workbook chứa code thực thi vì chúng ta không thể tham chiếu Sheet này từ "bên ngoài" nếu không chỉ rõ S00 thuộc Workbook nào.)

Với cách viết này bạn đã giảm đi 2 hành động thừa (Activate và Select). Tất nhiên ngoài gọn hơn, cách viết này không ảnh hưởng lớn đến tiến trình copy, nhưng thử hình dung xem mọi người sẽ gì về bạn khi bạn làm quá nhiều động tác thừa(!).*****

2. Khó khăn trong việc sửa code và bảo trì:

Đây là một trong các tiêu trí để hướng tới tính tối ưu trong lập trình. Hãy đơn giản hoá thủ tục bằng cách thuật lại những gì mình giải (giải thuật):
Mình chia thủ tục của bạn thành hai công đoạn;
Công đoạn 1: Cập nhật các giá trị và xác định ngày trong tuần
Công đoạn 2: Dựa vào ngày trong tuần tìm được để thực hiện lệnh sao chép đến vùng dữ liệu tương ứng.
Công đoạn 1 bạn rút gọn code như đã nói ở trên. Công đoạn 2 phương pháp cũng giống như thủ tục so sánh Ngaycapnhat với Cacthu trong chủ đề Khai báo biến và kiểm tra thứ trong tuần, bạn nên xác định trước vùng sao chép là vùng nào tương ứng với m sau đó mới tiến hành sao chép:

Mã:
Dim rgVungSaochep As Range, rgCopyTo As Range
 
Xét các trường hợp của m:
   Trường hợp m = 1
      Set rgVungSaochep = VungCopy1
      Set rgCopyTo = VungPaste1
   Trường hợp m = 2
      Set rgVungSaochep = VungCopy2
      Set rgCopyTo = VungPaste2
   Trường hợp m = 3
      Set rgVungSaochep = VungCopy3
      Set rgCopyTo = VungPaste3
   Trường hợp m = 4
      Set rgVungSaochep = VungCopy4
      Set rgCopyTo = VungPaste4
   Trường hợp m = 5
      Set rgVungSaochep = VungCopy5
      Set rgCopyTo = VungPaste5
   Trường hợp m = 6
      Set rgVungSaochep = VungCopy6
      Set rgCopyTo = VungPaste6
   Trường hợp m = 7
      Set rgVungSaochep = VungCopy7
      Set rgCopyTo = VungPaste7
Hết các trường hợp!
 
[COLOR=darkgreen]'Bây giờ tiến hành sao chép:[/COLOR]
rgVungSaochep.Copy 
rgCopyTo.PasteSpecial xlPaste... (theo kiểu gì đó!)
[COLOR=darkgreen]'Hoặc:[/COLOR]
rgVungSaochep.Copy rgCopyTo [COLOR=darkgreen]' Lúc này rgCopyTo đóng vai trò là  vùng dữ liệu đích  (Destination) 
[/COLOR]

Bạn sẽ nhận thấy rằng cách này có vẻ không những không rút ngắn thủ tục mà còn tạo thêm 2 biến trung gian. Đúng là dư thừa, song ngược lại nó rất rõ ràng và trong sáng vì trong mỗi trường hợp chúng ta chỉ đi tìm các đối tượng Range chứ không đan xen thêm hành động nào khác. Điều này giúp bạn hữu ích hơn trong việc bảo trì và cải tiến thủ tục (muốn làm việc tiếp với vùng dữ liệu sao chép chẳng hạn!).

 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom