Xin chào Gió Đông,
Dạ vâng, ^_^
Cơ quan của Oanh Thơ nghèo nên không có kinh phí mua phần mềm , do vậy mỗi người phải tự thân vận động bạn ạ.
Đáng buồn nhất là Oanh Thơ hỏi xong áp dụng OK là quên luôn không nhớ gì hết trơn ạ , mặc dù là đôi lúc đã dành tìm hiểu đến (T_T)
Sau 1 thời gian tham gia diễn đàn Oanh thơ cũng cảm thấy nơi đây: Thầy nhiều hơn Trò bạn ah
Một môi trường rất hữu ích, cảm giác thật tuyệt vời.
Sub TongHop()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Const TEN0 As String = "Tonghop" 'Ten sheet Tonghop
Dim wb As Workbook, ws As Worksheet, NB As String, NS As String
Dim tmp() As Variant, z As Long, r As Long, T As Variant
Dim KQ() As Variant, j As Long, k As Long, kMax As Long, maWS As String, tenWS As String
Set wb = ThisWorkbook: NB = wb.Name: NB = Left(NB, Len(NB) - 5)
ReDim KQ(1 To 1000000, 1 To 50)
For Each ws In wb.Worksheets
NS = ws.Name
If NS <> TEN0 Then 'Kiem tra: ten sheet <> ten sheet Tonghop
z = ws.Range("I" & ws.Rows.Count).End(xlUp).Row
If z > 9 Then
Erase tmp
tmp = ws.Range("E10:AW" & z).Value2: z = UBound(tmp, 1): kMax = UBound(tmp, 2)
maWS = ws.Range("K6"): tenWS = ws.Range("K7")
For r = 1 To z
T = tmp(r, 5)
If T <> Empty Then
j = j + 1
For k = 1 To kMax
KQ(j, k + 5) = tmp(r, k)
Next k
KQ(j, 1) = NB: KQ(j, 2) = NS
KQ(j, 3) = maWS: KQ(j, 4) = tenWS
End If
Next r
End If
End If
Next ws
If j Then
Sheets(TEN0).Range("B5").Resize(1000000, 50).ClearContents
Sheets(TEN0).Range("B5").Resize(j, 50) = KQ
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
p/s: Mỗi ngày oánh quả lẻ một bài rồi sẽ xong việc thôi...
Xin chào Gió Đông,
Dạ vâng, ^_^
Cơ quan của Oanh Thơ nghèo nên không có kinh phí mua phần mềm , do vậy mỗi người phải tự thân vận động bạn ạ.
Đáng buồn nhất là Oanh Thơ hỏi xong áp dụng OK là quên luôn không nhớ gì hết trơn ạ , mặc dù là đôi lúc đã dành tìm hiểu đến (T_T)
Sau 1 thời gian tham gia diễn đàn Oanh thơ cũng cảm thấy nơi đây: Thầy nhiều hơn Trò bạn ah
Một môi trường rất hữu ích, cảm giác thật tuyệt vời.
Sub TongHop()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Const TEN0 As String = "Tonghop" 'Ten sheet Tonghop
Dim wb As Workbook, ws As Worksheet, NB As String, NS As String
Dim tmp() As Variant, z As Long, r As Long, T As Variant
Dim KQ() As Variant, j As Long, k As Long, kMax As Long, maWS As String, tenWS As String
Set wb = ThisWorkbook: NB = wb.Name: NB = Left(NB, Len(NB) - 5)
ReDim KQ(1 To 1000000, 1 To 50)
For Each ws In wb.Worksheets
NS = ws.Name
If NS <> TEN0 Then 'Kiem tra: ten sheet <> ten sheet Tonghop
z = ws.Range("I" & ws.Rows.Count).End(xlUp).Row
If z > 9 Then
Erase tmp
tmp = ws.Range("E10:AW" & z).Value2: z = UBound(tmp, 1): kMax = UBound(tmp, 2)
maWS = ws.Range("K6"): tenWS = ws.Range("K7")
For r = 1 To z
T = tmp(r, 5)
If T <> Empty Then
j = j + 1
For k = 1 To kMax
KQ(j, k + 5) = tmp(r, k)
Next k
KQ(j, 1) = NB: KQ(j, 2) = NS
KQ(j, 3) = maWS: KQ(j, 4) = tenWS
End If
Next r
End If
End If
Next ws
If j Then
Sheets(TEN0).Range("B5").Resize(1000000, 50).ClearContents
Sheets(TEN0).Range("B5").Resize(j, 50) = KQ
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
p/s: Mỗi ngày oánh quả lẻ một bài rồi sẽ xong việc thôi...
Xin chào Gió Đông, Cảm ơn bạn đã góp ý,Oanh Thơ sẽ cố gắng hơn nữa.
Có 1 câu nói của 1 thành viên ở chữ ký,khiến cho tôi cũng nhớ mãi,có lẽ Oanh Thơ cũng như bạn ấy:
"Hỏi thì ngại mọi người chê mình dốt mà không hỏi thì sẽ dốt cả đời .Học hỏi là để vượt qua chính mình."
Xin chào befaint,
Bạn cho hỏi,code của bạn tôi sửa phần màu xanh thì có vấn đề gì không bạn?
Tôi sửa xong chạy chạy thử thì không báo lỗi gì cả. Sở dĩ tôi muốn sửa là vì sau dòng 102 thì cột I còn những dữ liệu khác nữa mà tôi không muốn xét đến.
Mã:
Sub TongHop()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Const TEN0 As String = "Tonghop" 'Ten sheet Tonghop
Dim wb As Workbook, ws As Worksheet, NB As String, NS As String
Dim tmp() As Variant, z As Long, r As Long, T As Variant
Dim KQ() As Variant, j As Long, k As Long, kMax As Long, maWS As String, tenWS As String
Set wb = ThisWorkbook: NB = wb.Name: NB = Left(NB, Len(NB) - 5)
ReDim KQ(1 To 1000000, 1 To 50)
For Each ws In wb.Worksheets
NS = ws.Name
If NS <> TEN0 Then 'Kiem tra: ten sheet <> ten sheet Tonghop
z = ws.Range("I" & ws.Rows.Count).End(xlUp).Row
If z > 9 Then
Erase tmp
tmp = ws.Range("E10:[COLOR=#0000ff]AW102[/COLOR][COLOR=#ff0000][/COLOR]").Value2: z = UBound(tmp, 1): kMax = UBound(tmp, 2)
maWS = ws.Range("K6"): tenWS = ws.Range("K7")
For r = 1 To z
T = tmp(r, 5)
If T <> Empty Then
j = j + 1
For k = 1 To kMax
KQ(j, k + 5) = tmp(r, k)
Next k
KQ(j, 1) = NB: KQ(j, 2) = NS
KQ(j, 3) = maWS: KQ(j, 4) = tenWS
End If
Next r
End If
End If
Next ws
If j Then
Sheets(TEN0).Range("B5").Resize(1000000, 50).ClearContents
Sheets(TEN0).Range("B5").Resize(j, 50) = KQ
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Xin chào befaint,
Bạn cho hỏi,code của bạn tôi sửa phần màu xanh thì có vấn đề gì không bạn?
Tôi sửa xong chạy chạy thử thì không báo lỗi gì cả. Sở dĩ tôi muốn sửa là vì sau dòng 102 thì cột I còn những dữ liệu khác nữa mà tôi không muốn xét đến.
z = ws.Range("I" & ws.Rows.Count).End(xlUp).Row
If z > 9 Then
End If
thì có phải biến z sẽ không cần thiết nữa phải không ạ, biến z sẽ không có ý nghĩa gì nữa,nếu đúng như vậy thì biến z của dòng code bên dưới có phải sửa thêm gì nữa không bạn?
z = ws.Range("I" & ws.Rows.Count).End(xlUp).Row
If z > 9 Then
End If
thì có phải biến z sẽ không cần thiết nữa phải không ạ, biến z sẽ không có ý nghĩa gì nữa,nếu đúng như vậy thì biến z của dòng code bên dưới có phải sửa thêm gì nữa không bạn?
For Each ws In wb.Worksheets 'Xét các ws trong wb
NS = ws.Name 'Lấy tên ws
If NS <> TEN0 Then 'Kiem tra: ten sheet <> ten sheet Tonghop
z = ws.Range("I" & ws.Rows.Count).End(xlUp).Row 'Xác định dòng cuối cùng từ dưới lên có dữ liệu ở cột I (1)
If z > 9 Then 'Kiểm tra điều kiện z>9 mới chạy tiếp, nếu z<=9 tức là (1) không có dữ liệu, chỉ có cái tiêu đề ở dòng 9
Erase tmp 'Xóa dữ liệu biến tmp
tmp = ws.Range("E10:AW" & z).Value2: z = UBound(tmp, 1): kMax = UBound(tmp, 2)
'Gán vùng dữ liệu "E10:AW" & z vào biến tmp
'Xác định kích thước chiều thứ nhất của mảng tmp(): z = UBound(tmp, 1) (2)
'Chú thích: Ở đây tận dụng biến z (không thêm biến), biến z sẽ có giá trị mới, giá trị ở (1) bị loại bỏ.
'Xác định kích thước chiều thức hai của mảng tmp(): kMax = UBound(tmp, 2)
maWS = ws.Range("K6"): tenWS = ws.Range("K7")
'Lấy giá trị mã và tên tại K6, K7
For r = 1 To z
'Chạy vòng lặp từ 1 tới z (giá trị z ở (2))
Code 2:
Mã:
For Each ws In wb.Worksheets
NS = ws.Name
If NS <> TEN0 Then 'Kiem tra: ten sheet <> ten sheet Tonghop
Erase tmp
tmp = ws.Range("E10:AW102").Value2: z = UBound(tmp, 1): kMax = UBound(tmp, 2)
'Gán vùng dữ liệu "E10:AW102" vào biến tmp
'Xác định kích thước chiều thứ nhất của mảng tmp(): z = UBound(tmp, 1) (*)
'Xác định kích thước chiều thức hai của mảng tmp(): kMax = UBound(tmp, 2)
maWS = ws.Range("K6"): tenWS = ws.Range("K7")
For r = 1 To z
'Chạy vòng lặp từ 1 tới z (giá trị z ở (*))
T = tmp(r, 5)
If T <> Empty Then
j = j + 1
For k = 1 To kMax
KQ(j, k + 5) = tmp(r, k)
Next k
KQ(j, 1) = NB: KQ(j, 2) = NS
KQ(j, 3) = maWS: KQ(j, 4) = tenWS
End If
Next r
End If
Next ws
For Each ws In wb.Worksheets 'Xét các ws trong wb
NS = ws.Name 'Lấy tên ws
If NS <> TEN0 Then 'Kiem tra: ten sheet <> ten sheet Tonghop
z = ws.Range("I" & ws.Rows.Count).End(xlUp).Row 'Xác định dòng cuối cùng từ dưới lên có dữ liệu ở cột I (1)
If z > 9 Then 'Kiểm tra điều kiện z>9 mới chạy tiếp, nếu z<=9 tức là (1) không có dữ liệu, chỉ có cái tiêu đề ở dòng 9
Erase tmp 'Xóa dữ liệu biến tmp
tmp = ws.Range("E10:AW" & z).Value2: z = UBound(tmp, 1): kMax = UBound(tmp, 2)
'Gán vùng dữ liệu "E10:AW" & z vào biến tmp
'Xác định kích thước chiều thứ nhất của mảng tmp(): z = UBound(tmp, 1) (2)
'Chú thích: Ở đây tận dụng biến z (không thêm biến), biến z sẽ có giá trị mới, giá trị ở (1) bị loại bỏ.
'Xác định kích thước chiều thức hai của mảng tmp(): kMax = UBound(tmp, 2)
maWS = ws.Range("K6"): tenWS = ws.Range("K7")
'Lấy giá trị mã và tên tại K6, K7
For r = 1 To z
'Chạy vòng lặp từ 1 tới z (giá trị z ở (2))
Code 2:
Mã:
For Each ws In wb.Worksheets
NS = ws.Name
If NS <> TEN0 Then 'Kiem tra: ten sheet <> ten sheet Tonghop
Erase tmp
tmp = ws.Range("E10:AW102").Value2: z = UBound(tmp, 1): kMax = UBound(tmp, 2)
'Gán vùng dữ liệu "E10:AW102" vào biến tmp
'Xác định kích thước chiều thứ nhất của mảng tmp(): z = UBound(tmp, 1) (*)
'Xác định kích thước chiều thức hai của mảng tmp(): kMax = UBound(tmp, 2)
maWS = ws.Range("K6"): tenWS = ws.Range("K7")
For r = 1 To z
'Chạy vòng lặp từ 1 tới z (giá trị z ở (*))
T = tmp(r, 5)
If T <> Empty Then
j = j + 1
For k = 1 To kMax
KQ(j, k + 5) = tmp(r, k)
Next k
KQ(j, 1) = NB: KQ(j, 2) = NS
KQ(j, 3) = maWS: KQ(j, 4) = tenWS
End If
Next r
End If
Next ws
Yeap!!
Cảm ơn befaint,
Các dòng chú thích ở mỗi dòng code tương ứng rất cần thiết và có giá trị rất lớn đối với tôi.
Nhờ đó mà tôi đã hiểu thêm nhiều hơn như tôi tưởng..nếu code nào cũng như thế này thì chả mấy chốc tôi không còn là Trò nữa, hihi =))
Xin chào befaint,
Sau một hồi ngâm cứu tôi có 2 thắc mắc sau, rất mong bạn chỉ dẫn thêm:
1.
Mã:
Dim wb As Workbook, ws As Worksheet, NB As String, NS As String
Dim tmp() As Variant, z As Long, r As Long, T As Variant
Dim KQ() As Variant, j As Long, k As Long, kMax As Long, maWS As String, tenWS As String
Set wb = ThisWorkbook: NB = wb.Name: NB = Left(NB, Len(NB) - 5) 'Ten file
[B]ReDim KQ[/B](1 To 1000000, 1 To 50)
ở trên đã khai báo Dim KQ() As Variant
ở dưới là: ReDim KQ(1 To 1000000, 1 To 50) ReDim KQ ở đây có vai trò gì ạ?
2.
Mã:
KQ(j, k + 5) = tmp(r, k)
Số 5 ở đây có phải là cột G trong sheet Tonghop?
Còn rất nhiều thắc mắc liên quan đến mảng tôi muốn tìm hiểu thêm, nhưng vấn đề này có lẽ chờ 1 dịp khác ạ.
Trả lời nôm na thế này cho dễ hiểu: Mảng có 2 loại mảng tĩnh và mảng động. Phân biệt nó như sau:
a) Khi số phần tử trong mảng được cho trước, ta có mảng tĩnh. Ví dụ Dim arr(1 to 10) ---> Số 1 và 10 cố định.
b) Mảng động ngược lại, khi số phần tử trong mảng chưa biết trước mà phải thông qua biến nào đó để tính toán. Khi ấy BẮT BUỘC phải dùng ReDim chứ Dim thì lỗi ngay. Ví dụ ReDim arr(1 to n) với n là biến nào đó
-----------------------------------
Vậy có thể thấy code trên ReDim là thừa bởi mảng trên là mảng tĩnh (chẳng có thứ gì "động đậy" cả). Sửa lại theo 1 trong 2 cách sau:
Hoặc: Dim KQ(1 To 1000000, 1 To 50) và bỏ ReDim
Hoặc: ReDim KQ(1 To 1000000, 1 To 50) và bỏ Dim
----------------------------------
Ngoài chỗ đó vẫn còn nhiều cái thừa và chưa hợp lý nữa, để bạn và tác giả tự nghiên cứu lấy
(1) Ban đầu khai báo biến KQ(), mới khai báo là mảng 2 chiều nhưng chưa biết kích thước của mảng đó.
(2) Redim KQ(): Khai báo rõ kích thước cho mảng KQ()
Bạn tìm trên diễn đàn cũng đã có hoặc từ khóa "how to use redim in vba"
Ở sheet "Tonghop" có 50 cột cần tổng hợp (B:AY)
Nên có ReDim KQ(1 To 1000000, 1 To 50)
Trong các sheet nhỏ có 45 cột cần dữ liệu (E:AW) và gán vào sheet "Tonghop" từ cột G tới cột AY (ứng với vị trí cột 6-50 của mảng KQ())
nên xét k=1 tới 45 thì KQ(j, k + 5)=tmp(r, k)
Tức là: KQ(j, từ 6 tới 50)=tmp(r, từ 1 tới 45)
Còn rất nhiều thắc mắc liên quan đến mảng tôi muốn tìm hiểu thêm, nhưng vấn đề này có lẽ chờ 1 dịp khác ạ.
Trả lời nôm na thế này cho dễ hiểu: Mảng có 2 loại mảng tĩnh và mảng động. Phân biệt nó như sau:
a) Khi số phần tử trong mảng được cho trước, ta có mảng tĩnh. Ví dụ Dim arr(1 to 10) ---> Số 1 và 10 cố định.
b) Mảng động ngược lại, khi số phần tử trong mảng chưa biết trước mà phải thông qua biến nào đó để tính toán. Khi ấy BẮT BUỘC phải dùng ReDim chứ Dim thì lỗi ngay. Ví dụ ReDim arr(1 to n) với n là biến nào đó
-----------------------------------
Vậy có thể thấy code trên ReDim là thừa bởi mảng trên là mảng tĩnh (chẳng có thứ gì "động đậy" cả). Sửa lại theo 1 trong 2 cách sau:
Hoặc: Dim KQ(1 To 1000000, 1 To 50) và bỏ ReDim
Hoặc: ReDim KQ(1 To 1000000, 1 To 50) và bỏ Dim
----------------------------------
Ngoài chỗ đó vẫn còn nhiều cái thừa và chưa hợp lý nữa, để bạn và tác giả tự nghiên cứu lấy
theo như tôi thấy: môi trường này là môi trường học hỏi giúp mọi người có thể hoàn thiện được khả năng của mình.
nếu một người nào đó: tất cả mọi thứ cái gì cũng biết cũng chưa chắc người đó đã tham gia diễn đàn này, phải không bạn?
(1) Ban đầu khai báo biến KQ(), mới khai báo là mảng 2 chiều nhưng chưa biết kích thước của mảng đó.
(2) Redim KQ(): Khai báo rõ kích thước cho mảng KQ()
Bạn tìm trên diễn đàn cũng đã có hoặc từ khóa "how to use redim in vba"
[/COLOR]
Ở sheet "Tonghop" có 50 cột cần tổng hợp (B:AY)
Nên có ReDim KQ(1 To 1000000, 1 To 50)
Trong các sheet nhỏ có 45 cột cần dữ liệu (E:AW) và gán vào sheet "Tonghop" từ cột G tới cột AY (ứng với vị trí cột 6-50 của mảng KQ())
nên xét k=1 tới 45 thì KQ(j, k + 5)=tmp(r, k)
Tức là: KQ(j, từ 6 tới 50)=tmp(r, từ 1 tới 45)
theo như tôi thấy: môi trường này là môi trường học hỏi giúp mọi người có thể hoàn thiện được khả năng của mình.
nếu một người nào đó: tất cả mọi thứ cái gì cũng biết cũng chưa chắc người đó đã tham gia diễn đàn này, phải không bạn?
------------
Cảm ơn befaint,
Tôi sẽ cố gắng tìm hiểu thêm theo hướng của bạn đã chỉ dẫn.
Có lẽ do thói quen đặt tên biến của mỗi người, ai đặt nấy hiểu, nấy nhớ. Ví dụ biến T, biến z ...
Cũng tương tự hoạt động của code trên, nhưng nếu đặt tên biến kiểu khác có lẽ dễ "đọc" hơn một chút:
I, J, K là các biến "chạy".
Rws, hay R có thể nghĩ đến "dòng"
sArr : mảng nguồn, dArr: Mảng đích (kết quả)
FileName: Tên File......
PHP:
Public Sub GPE()
Const TONGHOP As String = "Tonghop"
Dim Ws As Worksheet, sArr(), dArr(1 To 50000, 1 To 50)
Dim Rws As Long, I As Long, J As Long, K As Long, R As Long
Dim FileName As String, ShName As String, MaSheet As String, TenSheet As String
FileName = Left(ThisWorkbook.Name, InStr(ThisWorkbook.Name, ".") - 1)
For Each Ws In ThisWorkbook.Worksheets
If Ws.Name <> TONGHOP Then
With Ws
R = .Range("I1000000").End(xlUp).Row
If R > 9 Then
ShName = .Name: MaSheet = .Range("K6").Value: TenSheet = .Range("K7").Value
sArr = .Range("E10:E" & R).Resize(, 45).Value: Rws = UBound(sArr)
For I = 1 To Rws
If sArr(I, 5) <> Empty Then
K = K + 1
dArr(K, 1) = FileName: dArr(K, 2) = ShName
dArr(K, 3) = MaSheet: dArr(K, 4) = TenSheet
For J = 1 To 45
dArr(K, J + 5) = sArr(I, J)
Next J
End If
Next I
End If
End With
End If
Next Ws
With Sheets(TONGHOP)
.Range("B5").Resize(50000, 50).ClearContents
.Range("B5").Resize(K, 50) = dArr
End With
End Sub
Được thôi (chỉ sợ ít người thích nghe)
1> Thứ nhất: Ngay từ đầu đọc code là tôi đã thấy khá lằng nhằng về cách đặt tên biến khiến tôi biết đường nào mà lần
Tên biến cũng có quy định ngầm thế này: tiền tố đầu (từ 1 đến 3 ký tự) mô tả kiểu biến và luôn luôn viết thường, các ký tự sau đó mô tả công dụng của biến với ký tự đầu (hoặc vài ký tự sau đó) được viết hoa. Ví dụ:
wksMain ---> Biết ngay biến này là kiểu worksheet, có tên là Main hoặc có công dụng như một sheet chính lR hoặc lRow ---> Biến kiểu long, mô tả về chỉ số dòng aSource hoặc arrSource ---> biến Array mô tả vùng dữ liệu nguồn
vân vân....
2> Thứ hai: Nói về phép so sánh chuỗi: If NS <> TEN0 đây là phép so sánh rất chủ quan, bởi nếu đổi tên sheet thành TONGHOP thì phát biểu IF kia sẽ cho kết quả FALSE mà ta chưa chắc biết lý do tại sao. Cách an toàn là dùng UCase hoặc LCase
Mã:
Const TEN0 = "TONGHOP"
.......
If UCase(NS) <> TEN0 then
Ngoài ra, để chắc ăn cho người chạy code với bất cứ sự thay đổi tên sheet nào, ta nên vẽ 1 button lên sheet tổng hợp, chạy code thông qua button thì sẽ khỏi chạy đâu sai cả (vân vân.. và nhiều cách khác)
3> Thứ ba: kMax = UBound(tmp, 2) trong khi tmp = ws.Range("E10:AW" & z).Value2 là vùng cố định từ cột E đến AW ---> Suy ra kMax này ta luôn luôn biết trước là bao nhiêu cột rồi, vậy tại sao lại đưa vào vòng lập để tính toán?
----------------------------------
Vài góp ý nhỏ. Nhìn chung là code ổn nhưng tôi vẫn không thích tí nào về cách đặt tên biến của code này (chóng mặt, khó dò tìm...). Và cũng bởi chóng mặt, khó tìm nên nếu ai đó muốn sửa code thì chắc người ta thà viết lại từ đâu cho khỏe
Có lẽ do thói quen đặt tên biến của mỗi người, ai đặt nấy hiểu, nấy nhớ. Ví dụ biến T, biến z ...
Cũng tương tự hoạt động của code trên, nhưng nếu đặt tên biến kiểu khác có lẽ dễ "đọc" hơn một chút:
I, J, K là các biến "chạy".
Rws, hay R có thể nghĩ đến "dòng"
sArr : mảng nguồn, dArr: Mảng đích (kết quả)
FileName: Tên File......
PHP:
Public Sub GPE()Const TONGHOP As String = "Tonghop"Dim Ws As Worksheet, sArr(), dArr(1 To 50000, 1 To 50)Dim Rws As Long, I As Long, J As Long, K As Long, R As LongDim FileName As String, ShName As String, MaSheet As String, TenSheet As StringFileName = Left(ThisWorkbook.Name, InStr(ThisWorkbook.Name, ".") - 1)For Each Ws In ThisWorkbook.Worksheets If Ws.Name <> TONGHOP Then With Ws R = .Range("I1000000").End(xlUp).Row If R > 9 Then ShName = .Name: MaSheet = .Range("K6").Value: TenSheet = .Range("K7").Value sArr = .Range("E10:E" & R).Resize(, 45).Value: Rws = UBound(sArr) For I = 1 To Rws If sArr(I, 5) <> Empty Then K = K + 1 dArr(K, 1) = FileName: dArr(K, 2) = ShName dArr(K, 3) = MaSheet: dArr(K, 4) = TenSheet For J = 1 To 45 dArr(K, J + 5) = sArr(I, J) Next J End If Next I End If End With End IfNext WsWith Sheets(TONGHOP) .Range("B5").Resize(50000, 50).ClearContents .Range("B5").Resize(K, 50) = dArrEnd WithEnd Sub
Cảm ơn Ba Tê đã giúp tôi có thêm 1 sự lựa chọn và 1 cách để giúp tôi tiếp cận với code.
Tôi đã chạy thử code trên của bạn,kết quả cũng giống như code của bạn befaint (đúng với với mong muốn của tôi)
Nhìn qua code của bạn và befaint không gì khác nhau nhiều về thuật toán ?
Nhưng code của bạn tốc độ có phần nhanh hơn của bạn befaint 1 chút.
Tôi sẽ cố gắng dành thời gian tìm hiểu thêm vì sao lại như vậy.
Nếu gì vướng mắc mong lại được các bạn giúp đỡ.
Được thôi (chỉ sợ ít người thích nghe)
1> Thứ nhất: Ngay từ đầu đọc code là tôi đã thấy khá lằng nhằng về cách đặt tên biến khiến tôi biết đường nào mà lần
Tên biến cũng có quy định ngầm thế này: tiền tố đầu (từ 1 đến 3 ký tự) mô tả kiểu biến và luôn luôn viết thường, các ký tự sau đó mô tả công dụng của biến với ký tự đầu (hoặc vài ký tự sau đó) được viết hoa. Ví dụ:
wksMain ---> Biết ngay biến này là kiểu worksheet, có tên là Main hoặc có công dụng như một sheet chính
lR hoặc lRow ---> Biến kiểu long, mô tả về chỉ số dòng
aSource hoặc arrSource ---> biến Array mô tả vùng dữ liệu nguồn
vân vân....
2> Thứ hai: Nói về phép so sánh chuỗi: If NS <> TEN0 đây là phép so sánh rất chủ quan, bởi nếu đổi tên sheet thành TONGHOP thì phát biểu IF kia sẽ cho kết quả FALSE mà ta chưa chắc biết lý do tại sao. Cách an toàn là dùng UCase hoặc LCase
Mã:
Const TEN0 = "TONGHOP"
.......
If UCase(NS) <> TEN0 then
Ngoài ra, để chắc ăn cho người chạy code với bất cứ sự thay đổi tên sheet nào, ta nên vẽ 1 button lên sheet tổng hợp, chạy code thông qua button thì sẽ khỏi chạy đâu sai cả (vân vân.. và nhiều cách khác)
3> Thứ ba: kMax = UBound(tmp, 2) trong khi tmp = ws.Range("E10:AW" & z).Value2 là vùng cố định từ cột E đến AW ---> Suy ra kMax này ta luôn luôn biết trước là bao nhiêu cột rồi, vậy tại sao lại đưa vào vòng lập để tính toán?
----------------------------------
Vài góp ý nhỏ. Nhìn chung là code ổn nhưng tôi vẫn không thích tí nào về cách đặt tên biến của code này (chóng mặt, khó dò tìm...). Và cũng bởi chóng mặt, khó tìm nên nếu ai đó muốn sửa code thì chắc người ta thà viết lại từ đâu cho khỏe
Cảm ơn ndu96081631, đã chỉ dẫn.
Tôi là người hỏi nên chắc chắn sẽ tôi là người thích nghe,như vậy là đủ phải không bạn?
Nên bạn không phải lo sợ đâu ạ , tôi đang chưa có kiến thức gì về code, chưa thể nhìn nhận và tự giải quyết được các vấn đề liên quan đến code nên có có ý muốn học hỏi dần dần. Trong quá trình tiếp cận khó có thể tránh khỏi những câu hỏi ngớ ngẩn, vì thế tôi rất mong các bạn chỉ dẫn và góp ý nếu nhìn thấy vấn đề ...
2.Bạn có thể giải thích thêm dòng này được không ạ:
Ngoài ra, để chắc ăn cho người chạy code với bất cứ sự thay đổi tên sheet nào, ta nên vẽ 1 button lên sheet tổng hợp, chạy code thông qua button thì sẽ khỏi chạy đâu sai cả (vân vân.. và nhiều cách khác)
Việc chạy code thông qua button trên sheet"Tonghop" và chạy Sub trực tiếp trong cửa sổ soạn thảo code thì có gì khác nhau vậy, ý tôi muốn hỏi là chạy "code thông qua button thì sẽ khỏi chạy đâu sai cả..." là để có thể kiểm soá dễ dàng phát hiện được sự sai lệch?
Việc chạy code thông qua button trên sheet"Tonghop" và chạy Sub trực tiếp trong cửa sổ soạn thảo code thì có gì khác nhau vậy, ý tôi muốn hỏi là chạy "code thông qua button thì sẽ khỏi chạy đâu sai cả..." là để có thể kiểm soá dễ dàng phát hiện được sự sai lệch?
Trong cửa sổ vba mà chạy đoạn trên thì cứ sheet (xét cả workbook) nào được active (hiện hành) thì gán A1=1
Để chắc ăn thì gán nó vào cái nút ở sheet chỉ định cần chạy sub trên thì chỉ định gán A1=1 ở sheet có nút đó.
Hoặc viết chỉ định đích danh workbook.worksheet.range/cell
Mã:
Sub vidu()
Thisworkbook.sheets(1).range("A1")=1
End sub
thì không quan tâm sheet nào đang active, khi chạy đoạn đó trong cửa sổ vba đều chỉ gán A1=1 ở sheets(1) của workbook hiện hành.
Việc chạy code thông qua button trên sheet"Tonghop" và chạy Sub trực tiếp trong cửa sổ soạn thảo code thì có gì khác nhau vậy, ý tôi muốn hỏi là chạy "code thông qua button thì sẽ khỏi chạy đâu sai cả..." là để có thể kiểm soá dễ dàng phát hiện được sự sai lệch?
Bởi Button nằm tại sheet Tonghop nên đương nhiên bạn phải "đứng" tại sheet Tonghop mới chạy được. Và người ta sẽ có cách viết code đại khái thế này: Sheet nào có chứa cái Button thì sheet đó chính là sheet Tonghop (cho dù nó hổng phải tên Tonghop cũng không sao) và code bắt buộc phải chạy thông qua button chứ không thể chạy từ cửa sổ VBA
Như vậy sẽ rất là.. ổn
--------------------------------
Với bạn hoặc những ai mới bắt đầu với lập trình thì "nên thế nào cũng được" hoàn toàn không có vấn đề, miễn ra được kết quả là tốt rồi
Với rất nhiều thành viên am hiểu lập trình thì điều đó hoàn toàn không thể chấp nhận (trừ phi bạn đủ tài "chế" ra chuẩn mực mới khiến cả thế giới phải làm theo)
Nói nôm na như việc quản lý tại 1 cty: nếu mọi thứ đều tuân theo 1 chuẩn mực cho trước thì dễ quản lý hơn thay vì mạnh ai nấy làm theo ý mình, đúng không?
Xem chừng cũng hơi khó hiểu. Thôi thì thì làm cái thí nghiệm để minh họa nhé!
Đại khái code trong file đính kèm dưới đây sẽ lấy dữ liệu tại cell A1 của tất cả các sheet rồi đưa vào cột A của sheet hiện hành (sheet chứa button). Code chỉ chạy khi bạn nhấn vào button, ngoài ra cho dù bạn chạy code từ cửa sổ VBA hay nhấn Alt + F8 để chạy đều không được. Từ đây bất kể bạn dời sheet đi đâu hay đổi tên sheet thành thứ gì cũng được, miễn sheet đó có chứa cái Button thì code mới chạy
Mục đích của tôi là: định vị tên sheet Tonghop theo cách khác an toàn hơn
Ahihi!
Cảm ơn befaint , cảm ơn ndu96081631,
Đến giờ phút này, qua các ví dụ của 2 bạn tôi đã thấu được vấn đề:
"Việc chạy code thông qua button trên sheet"
-----------
Cứ tưởng học trên này không mất bất cứ 1 khoản phí nào.
Ai ngờ kết quả sau 1 buổi tìm hiểu về code thì đã mất 20k tiền mua "Panadol", chắc vấn đề này chưa dừng lại ở đây..
Nếu không có sự hỗ trợ chỉ dẫn tận tình của các bạn chắc tôi còn mệt dài và nặng gấp nhiều lần hơn thế.