Nhờ sửa Code link khối lượng

Liên hệ QC

tuan_anhbm

Thành viên thường trực
Tham gia
16/7/09
Bài viết
253
Được thích
1,605
Chào các cư dân GPE & các cao thủ VBA!
Tôi có 1 file dự toán xây dựng bằng Excel, trong đó có sử dụng Code (VBA) để thực hiện 1 công việc: “Link khối lượng từ bảng khối lượng (BKL) sang bảng phân tích vật tư (PTVT)”.
Mình có gửi file kèm theo để anh em kiểm tra cho tiện.
Nội dung:

Sub LinkKL()
'Noi dung: Link kh.luong tu bang KL qua bang PTVT
Application.ScreenUpdating = False
Dim m As Long, n As Long
m = 7
For n = 7 To Sheets("PTVT").[C65000].End(xlUp).Row
If Sheets("PTVT").Range("A" & n) <> "" Then
If Sheets("BKL").Range("E" & m) = "" Then m = m + 1
If Sheets("BKL").Range("E" & m) <> "" Then
Sheets("PTVT").Range("E" & n) = "=BKL!R" & m & "C5"
End If
m = m + 1
End If
Next
Application.ScreenUpdating = True
End Sub
Sau khi thử nghiệm cho kết quả:
- Nếu trong bảng kh.lượng (BKL) có <=1 dòng diễn giải thì KL bên bảng PTVT cho kết quả đúng.
- Nếu trong bảng kh.lượng có >= 2 dòng diễn giải (ví dụ: nếu dòng 8, 9, 10... cũng là dòng diễn giải) thì KL bên bảng PTVT sẽ bị sai.

Vậy nhờ anh em kiểm tra cái Sub trên xem có lỗi gì nhé.
(dòng diễn giải là dòng không có MHDG và không có KL. VD: dòng 7 - BKL đang là dòng diễn giải)

Ghi chú:
1- Trong file gốc có nhiềt Sheet nhưng đã cắt bớt 1 số Sheet cho gọn, chỉ còn 2 Sheet: BKL và PTVT, và cũng có nhiều module VBA nhưng cũng cắt bớt, chỉ trích đoạn từng vấn đề chưa ổn.
2- Yêu cầu là kết quả sau khi chạy Code trong bảng PTVT phải ở dạng link, VD: ở ô E7 của bảng PTVT sẽ có công thức: "=BKL!E..." v.v... để khi thay đổi dữ liệu trong bảng BKL thì sẽ tự thay đổi trong bảng PTVT mà không cần phải chạy lại.

Nhờ anh em trong diễn đàn kiểm tra và Edit cho cái Sub này, cảm ơn.
(xin anh em down lại file đã chuyển font Unicode)
------------
Tuấn Anh.
 
Lần chỉnh sửa cuối:
Dử liệu của bạn có mã trùng... vậy nếu gặp trường hợp trùng thì dựa vào cái gì để phân biệt? Dựa vào nội dung công việc chăng? Nhưng tôi lại thấy nội dung ở 2 sheet không đồng nhất ---> Bạn xem lại nhé!
Bài này lý ra dùng AutoFilter để lọc cũng không có vấn đề, có điều dử liệu lung tung quá (khi vầy khi khác) chẳng biết sao mà làm.... Đã vậy font chử gì khó đọc quá
 
Upvote 0
Chào bạn ndu960...
Trích: “Dử liệu của bạn có mã trùng... vậy nếu gặp trường hợp trùng thì dựa vào cái gì để phân biệt? Dựa vào nội dung công việc chăng? Nhưng tôi lại thấy nội dung ở 2 sheet không đồng nhất”
Xin bạn hiểu cho: 1- Trong 1 dự toán xây dựng chuyện “mã hiệu trùng nhau” là chuyện “thường ngày ở huyện”, dường như bất cứ 1 dự toán nào cũng có mã hiệu trùng nên không thể căn cứ vào sự khác biệt của mã hiệu; 2- Cũng không thể dựa vào “nội dung công việc” được vì xác xuất này vẫn có thể xảy ra. Mình muốn dựa trên sự tồn tại theo thứ tự của các mã hiệu giữa 2 bảng.
Thực ra mình đã có 2 giải pháp cho vấn đề này nhưng thấy chưa ưng ý lắm, (Sub mình Post là giải pháp của anh Phương - mà các member thường gặp trên diễn đàn - gởi cho, mình thấy nó chạy rất nhanh nên muốn hiệu chỉnh để sử dụng mà ko biết làm sao).
Tiện đây mình Post 2 phương pháp trước đây của mình để bạn tham khảo và cho ý kiến như sau:
- PP 1: Dòng vòng lặp để gán kết quả dựa trên sự tồn tại theo thứ tự của các mã hiệu:
Sub LinkKL1()
Application.ScreenUpdating = False
Sheets("BKL").Select
Range("A7").Select
If ActiveCell = "" Then Selection.End(xlDown).Select
Sheets("PTVT").Select
Range("E7").Select
If ActiveCell.Offset(0, -4) = "" Then Selection.Offset(0, -4).End(xlDown).Offset(0, 4).Select
Do Until ActiveCell.Offset(0, -4) = "."
Sheets("BKL").Select
Selection.Offset(0, 4).Copy
Selection.Offset(1, 0).Select
If ActiveCell = "" Then Selection.End(xlDown).Select
Sheets("PTVT").Select
ActiveSheet.Paste Link:=True
Selection.Offset(1, 0).Select
If ActiveCell.Offset(0, -4) = "" Then Selection.Offset(0, -4).End(xlDown).Offset(0, 4).Select
Loop
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Cách này test thử OK, nhưng với dữ liệu lớn (~500 công việc) thì chạy hơi bị chậm.
- PP 2:đặt STT tạm trong cột H của bảng PTVT (= STT trong bảng KL), rồi dùng hàm dò tìm VLOOKUP để gán kết quả.
Sub LinkKL2()
'1. Ghi STT vao cot STT - bang KL
Sheets("BKL").Select
Range([B7], [B20000].End(xlUp)).Offset(0, -1).Select
Columns("B:B").AutoFilter
Selection.AutoFilter Field:=1, Criteria1:="<>"
Selection = "=MAX(R7C:R[-1]C)+1"
Columns("B:B").AutoFilter
If Range("B7") <> "" Then
Range("B7").Offset(0, -1) = 1
Else: Range("B7").End(xlDown).Offset(0, -1) = 1
End If
Range("A1").Select
'2. Ghi STT vao cot STT - bang PTVT
Sheets("PTVT").Select
If Columns("H:H").Hidden = True Then Columns("H:H").Hidden = False
Columns("H:H").ClearContents
Range([A7], [A20000].End(xlUp)).Offset(0, 7).Select
Columns("A:A").AutoFilter
Selection.AutoFilter Field:=1, Criteria1:="<>"
Selection = "=MAX(R7C:R[-1]C)+1"
If [A7] <> "" Then
[A7].Offset(0, 7) = 1
Else: [A7].End(xlDown).Offset(0, 7) = 1
End If
'3. Link KL tu bang KL qua bang PTVT
With Sheets("BKL")
eR = .Range("B20000").End(xlUp).Row
End With
Selection.Offset(0, -3).Select
Selection.AutoFilter Field:=1, Criteria1:="<>"
Selection = "= VLOOKUP(RC[3],BKL!R7C1:R" & eR & "C5,5,0)"
Columns("A:A").AutoFilter
Columns("H:H").Hidden = True
Range("A1").Select
MsgBox "Da link xong khoi luong tu bang KL qua bang PTVT", , "OK"
End Sub
Kiểm tra cũng cho kết quả OK, chạy nhanh nhưng có nhược điểm là: nếu vì 1 lý do gì mà sửa STT bên bảng KL thì Kh.lượng trong bảng PTVT sẽ bị khác. Hơn nữa sẽ tạo thêm 1 cột dữ liệu trung gian (cột H).
Vì vậy cái mình muốn là có 1 Code chuyên nghiệp hơn, chạy nhanh hơn và phải link được trực tiếp theo kiểu “=BKL!E...” là tốt nhất.
-------------
Vấn đề font chử: thành thật ghi nhận góp ý của bạn, mình đã đổi font rồi, bạn down lại file và xem lại giúp mình nhé.
---------------
Very Thank.
Tuan Anh.
 
Lần chỉnh sửa cuối:
Upvote 0
Chào bạn!
Việc tìm kiếm thường dựa vào 1 đặc điểm nhận dạng nào đó, và nó phải là duy nhất ---> Nếu mã của bạn bị trùng thì bạn phải xây dựng thêm 1 mã nhận dạng nữa sao cho nó là duy nhất ---> thế mới tìm được chứ
Bạn thử nghĩ xem, bạn tìm ông A huyện B thì tìm thế nào nếu bạn không nói được tên xã, phường, số nhà hoặc những đặc điểm nhận dang riêng biệt chỉ có ở ông A (CA chắc cũng bó tay)
Về phương án 2 của bạn, nếu đã dùng VLOOKUP sao bạn không gõ công thức trực tiếp vào bảng tính luôn? ---> cần code làm gì (vì đàng nào nó vẫn là công thức)
Nếu bạn vẫn nhất định giữ nguyên dử liệu như trên, tôi nghĩ khó mà có 1 giải pháp hoàn hảo
 
Upvote 0
Chào bạn ndu960...,

Có lẽ bạn chưa thử Sub LinkKL1 của mình hay sao? nó vẫn gán chính xác mà không cần thêm điều kiện gì mà.
Còn về việc sao không dùng công thức: Là do đây là 1 phần trong "chương trình con" của mình (tạm gọi), mình đã tạo tương đối hoàn chỉnh 1 ch.trình dự thầu, gắn các module với các menu lệnh, sau khi hoàn thành, mình chỉ kích chuột vào các menu là hoàn thành công việc, không phải can thiệp bất cứ công việc thủ công nào.
----------------------
Công việc này giống như nhiệm vụ của 1 người phát báo:
- Người phát báo có nhiệm vụ phát báo cho N hộ trong 1 dãy phố. Các hộ này có thể nằm liền kề hoặc cách 1 đoạn đường trống lại có 1 căn hộ.
- Số lượng báo cần phát = số lượng hộ cần nhận báo trên con phố đó (= N). Và cũng đã được xắp theo thứ tự từ 1 -> N, người phát báo chỉ việc mang xấp báo đi từ đầu phố đến cuối phố, nếu cứ thấy có nhà là quẳng vào đó 1 tờ báo (không thấy nhà thì thôi). Cứ thế, hộ số 1 nhận tờ báo số 1, ... hộ thứ N nhận tờ báo thứ N. Như vậy anh ta sẽ không cần quan tâm xem chủ nhà (hay số nhà) trùng tên nhau hay ko.
- Hoàn thành nhiệm vụ.

Bạn thấy như vậy được không? thử giúp mình xem sao?
Thân.
 
Lần chỉnh sửa cuối:
Upvote 0
Chào bạn ndu960...,

Có lẽ bạn chưa thử Sub LinkKL1 của mình hay sao? nó vẫn gán chính xác mà không cần thêm điều kiện gì mà.
Còn về việc sao không dùng công thức: Là do đây là 1 phần trong "chương trình con" của mình (tạm gọi), mình đã tạo tương đối hoàn chỉnh 1 ch.trình dự thầu, gắn các module với các menu lệnh, sau khi hoàn thành, mình chỉ kích chuột vào các menu là hoàn thành công việc, không phải can thiệp bất cứ công việc thủ công nào.
----------------------
Công việc này giống như nhiệm vụ của 1 người phát báo:
- Người phát báo có nhiệm vụ phát báo cho N hộ trong 1 dãy phố. Các hộ này có thể nằm liền kề hoặc cách 1 đoạn đường trống lại có 1 căn hộ.
- Số lượng báo cần phát = số lượng hộ cần nhận báo trên con phố đó (= N). Và cũng đã được xắp theo thứ tự từ 1 -> N, người phát báo chỉ việc mang xấp báo đi từ đầu phố đến cuối phố, nếu cứ thấy có nhà là quẳng vào đó 1 tờ báo (không thấy nhà thì thôi). Cứ thế, hộ số 1 nhận tờ báo số 1, ... hộ thứ N nhận tờ báo thứ N. Như vậy anh ta sẽ không cần quan tâm xem chủ nhà (hay số nhà) trùng tên nhau hay ko.
- Hoàn thành nhiệm vụ.

Bạn thấy như vậy được không? thử giúp mình xem sao?
Thân.
Nếu đã như thế thì dùng công thức như thế này:
Mã:
=IF(A7="","",VLOOKUP(COUNTA($A$7:A7),BKL!$A$7:$I$32,5,))
Và đưa nó vào Macro:
PHP:
Sub LinkKL()
Range(Sheets("PTVT").[E7], Sheets("PTVT").[C65536].End(xlUp).Offset(, 2)).FormulaR1C1 = _
        "=IF(RC[-4]="""","""",VLOOKUP(COUNTA(R7C1:RC[-4]),BKL!R7C1:R" & Sheets("BKL").[B65536].End(xlUp).Row & "C9,5,))"
End Sub
 
Upvote 0
Công việc này giống như nhiệm vụ của 1 người phát báo:
- Người phát báo có nhiệm vụ phát báo cho N hộ trong 1 dãy phố. Các hộ này có thể nằm liền kề hoặc cách 1 đoạn đường trống lại có 1 căn hộ.
- Số lượng báo cần phát = số lượng hộ cần nhận báo trên con phố đó (= N). Và cũng đã được xắp theo thứ tự từ 1 -> N, người phát báo chỉ việc mang xấp báo đi từ đầu phố đến cuối phố, nếu cứ thấy có nhà là quẳng vào đó 1 tờ báo (không thấy nhà thì thôi). Cứ thế, hộ số 1 nhận tờ báo số 1, ... hộ thứ N nhận tờ báo thứ N. Như vậy anh ta sẽ không cần quan tâm xem chủ nhà (hay số nhà) trùng tên nhau hay ko.
- Hoàn thành nhiệm vụ.

Bạn thấy như vậy được không? thử giúp mình xem sao?
Thân.
Nếu bạn nói thế có nghĩa là quét từ trên xuống dưới, cứ gặp dử liệu thì lấy mà không quan tâm mã hay nội dung gì cả, đúng không?
PHP:
Sub LinkKL()
  Dim BKL As Worksheet, PTVT As Worksheet, fRng As Range, Clls As Range
  Set BKL = Sheets("BKL"): Set PTVT = Sheets("PTVT")
  On Error Resume Next
  BKL.[B65536].End(xlUp)(2) = " "
  With Range(PTVT.[A7], PTVT.[A65536].End(xlUp))
    Set fRng = Range(BKL.[B7], BKL.[B65536].End(xlUp))
    For Each Clls In .SpecialCells(2)
      Set fRng = Range(fRng(2), BKL.[B65536].End(xlUp)).SpecialCells(2)
      Clls(, 5).Value = "=BKL!" & fRng(1, 4).Address(0, 0)
    Next
  End With
  BKL.[B65536].End(xlUp)(2).Clear
End Sub
 

File đính kèm

Upvote 0
Code cũ hơi lằng nhằng 1 chút, tôi sửa lại thế này nhé:
PHP:
Sub LinkKL()
  Dim Src As Range, fRng As Range, Clls As Range
  On Error Resume Next
  Set Src = Range(Sheets("BKL").[B10], Sheets("BKL").[B65536].End(xlUp))
  Set fRng = Sheets("BKL").Range("B10")
  With Range(Sheets("PTVT").[A7], Sheets("PTVT").[A65536].End(xlUp))
    For Each Clls In .SpecialCells(2)
      Clls(, 5).Value = "=BKL!" & fRng(1, 4).Address(0, 0)
      If Intersect(fRng(2), Src) Is Nothing Then Exit Sub
      Set fRng = Range(fRng(2), Sheets("BKL").Cells(65536, fRng.Column)).SpecialCells(2)
    Next
  End With
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Gửi bạn huuthang_bd !
Giải pháp của bạn huuthang_bd cũng hay đấy nhỉ: Chỉ 1 chiêu là xong!
Nhưng bạn ơi Code của bạn lại đưa công thức vào tất cả ác ô trống -> như vậy sẽ làm nặng file và nó còn liên quan đến những vấn đề khác...
Huynh xuất chiêu thêm 1 chưởng nữa để hô biến hết các công thức trong các ô trống đi đuợc ko ? (cho mình xin thêm 1 dòng lệnh vào trong Sub cũ nhé).
Thank you.
------------------
Gửi bạn ndu960...
Mình đã test thử file bạn sửa, chạy ngon rùi, rất nhanh, rất ưng ý. Đúng là chuyên gia GPE có khác.
Nhưng nè bạn ơi, check Code lại cho mình 1 chút nữa đi: tại sao Sub này nó đúng trong file hiện tại mà sai trong 1 file tương tự ? Hình như là nếu có đúng 3 dòng diễn giải kể từ dòng thứ 7 trong bảng khối lượng thì kết quả = true (đúng), ngược lại cho kết quả sai?
Mình muốn là mọi trường hợp (có bao nhiêu hoặc ko có dòng diễn giải nào) thì kết quả vẫn đúng. Bạn kiểm tra giúp mình trong file đính kèm nhé.
Thank you & Thank you.
Tuan_anhbm
Nhân tài như lá mùa thu, còn hào kiệt thời nào chả có...
 
Lần chỉnh sửa cuối:
Upvote 0
Gửi bạn huuthang_bd !
Giải pháp của bạn huuthang_bd cũng hay đấy nhỉ: Chỉ 1 chiêu là xong!
Nhưng bạn ơi Code của bạn lại đưa công thức vào tất cả ác ô trống -> như vậy sẽ làm nặng file và nó còn liên quan đến những vấn đề khác...
Huynh xuất chiêu thêm 1 chưởng nữa để hô biến hết các công thức trong các ô trống đi đuợc ko ? (cho mình xin thêm 1 dòng lệnh vào trong Sub cũ nhé).
Thank you.
------------------
Gửi bạn ndu960...
Mình đã test thử file bạn sửa, chạy ngon rùi, rất nhanh, rất ưng ý. Đúng là chuyên gia GPE có khác.
Nhưng nè bạn ơi, check Code lại cho mình 1 chút nữa đi: tại sao Sub này nó đúng trong file hiện tại mà sai trong 1 file tương tự ? Hình như là nếu có đúng 3 dòng diễn giải kể từ dòng thứ 7 trong bảng khối lượng thì kết quả = true (đúng), ngược lại cho kết quả sai?
Mình muốn là mọi trường hợp (có bao nhiêu hoặc ko có dòng diễn giải nào) thì kết quả vẫn đúng. Bạn kiểm tra giúp mình trong file đính kèm nhé.
Thank you & Thank you.
Tuan_anhbm
Nhân tài như lá mùa thu, còn hào kiệt thời nào chả có...
Muốn vậy thì sửa lại thế này:
PHP:
Sub LinkKL()
    Range(Sheets("PTVT").[A7], Sheets("PTVT").[A65536].End(xlUp)).SpecialCells(xlCellTypeConstants, 23).Offset(, 4).FormulaR1C1 = "=VLOOKUP(COUNTA(R7C1:RC[-4]),BKL!R7C1:R" & Sheets("BKL").[B65536].End(xlUp).Row & "C9,5,)"
End Sub
 
Upvote 0
Gửi bạn ndu960...
Mình đã test thử file bạn sửa, chạy ngon rùi, rất nhanh, rất ưng ý. Đúng là chuyên gia GPE có khác.
Nhưng nè bạn ơi, check Code lại cho mình 1 chút nữa đi: tại sao Sub này nó đúng trong file hiện tại mà sai trong 1 file tương tự ? Hình như là nếu có đúng 3 dòng diễn giải kể từ dòng thứ 7 trong bảng khối lượng thì kết quả = true (đúng), ngược lại cho kết quả sai?
Bạn nói sai là sai chổ nào? Sao không đưa file mà bạn nói sai ấy lên... Mà bạn nói DÒNG DIỂN GIẢI là dòng nào thế... tôi xem trong file chẳng thấy chổ nào cả
 
Upvote 0
NDU960... Mình đã Up file lên rồi mà, bạn qua trang 1, file Excel "VD(3).xls" đó!
(dòng diễn giải là dòng chỉ có dữ liệu trong cột nội dung công việc, không có mã hiệu, đơn vị và khối lượng. VD: dòng 7, 8, 9; 20, 21, 22 ở bảng khối lượng đang là các dòng diễn giải)
 
Lần chỉnh sửa cuối:
Upvote 0
NDU960... Mình đã Up file lên rồi mà, bạn qua trang 1, file Excel "VD(3).xls" đó!
(dòng diễn giải là dòng chỉ có dữ liệu trong cột nội dung công việc, không có mã hiệu, đơn vị và khối lượng. VD: dòng 7, 8, 9; 20, 21, 22 ở bảng khối lượng đang là các dòng diễn giải)
Nhưng code tôi đưa lên đâu có "ăn nhậu" gì với mấy dòng diển giải mà bạn vừa nói!
Tôi làm theo cách: Tìm theo mã từ trên xuống dưới, cứ "gặp" là "lấy" ---> Giống như "phát thư" mà bạn đã nói, thấy có MÃ thì lấy KHỐI LƯỢNG
 
Upvote 0
Chào ndu960...
Mình đã test lại sao vẫn thấy vậy? Thôi để tự mình "ngâm cứu" tiếp cũng được. Dù sao cũng cảm ơn bạn rất nhiều.
-----------------------------------------------------------------
Nhắn chung các bạn nào là "dân xây dựng":
Mình vừa hoàn thành về cơ bản file Excel để dùng cho việc điều tiến độ thi công trong xây dựng ở bên phần Excel và kỹ thuật.
(http://www.giaiphapexcel.com/forum/showthread.php?p=175833#post175833)
Vậy bạn nào quan tâm load về dùng thử và cho ý kiến góp ý nha!
Thank...
 
Upvote 0
Web KT

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

Back
Top Bottom