0905744404
Thành viên thường trực




- Tham gia
- 26/10/10
- Bài viết
- 333
- Được thích
- 107
- Nghề nghiệp
- Trước là : Thủ Kho - còn giờ thì :"Tài Xế"
Em nhờ mọi cả nhà giúp em viết code chuyển từ hàm Vlookup() sang Code VBA
Nếu dùng VBA để thay thế một hàm của Excel, xin bạn hãy quên thói quen này đi, bởi hàm trong Excel tôi tin rằng nó đã rất tối ưu, bạn viết không thể chạy nhanh bằng hàm của anh Bill đâu!Em nhờ mọi cả nhà giúp em viết code chuyển từ hàm Vlookup() sang Code VBA
Nếu đưa hàm vlookup vào trong code thì còn được chứ đi viết lại 1 hàm giống vlookup là điều không tưởng. Bởi vì vlookup là do cả 1 tập thể những lập trình viên kiệt xuất tạo ra. Còn chúng ta...Em nhờ mọi cả nhà giúp em viết code chuyển từ hàm Vlookup() sang Code VBA
Mình đã nhầm: Nhờ bạn giúp mình cách đưa hàm Vlookup vào trong code vớiNếu đưa hàm vlookup vào trong code thì còn được chứ đi viết lại 1 hàm giống vlookup là điều không tưởng. Bởi vì vlookup là do cả 1 tập thể những lập trình viên kiệt xuất tạo ra. Còn chúng ta...
Có 2 dạng đưa vào code:Mình đã nhầm: Nhờ bạn giúp mình cách đưa hàm Vlookup vào trong code với
Em muốn thực hiện phương pháp thứ 2 tức:"Thực hiện trực tiếp công thức trên code, khi gán giá trị xuống sheet, thì chỉ là kết quả được tính toán."Có 2 dạng đưa vào code:
1) Dạng chuyển công thức từ code vào sheet, tức sau khi chạy code thì tại một ô nào đó chứa công thức.
2) Thực hiện trực tiếp công thức trên code, khi gán giá trị xuống sheet, thì chỉ là kết quả được tính toán.
Vậy bạn muốn phương thức nào?
Bạn dùng đoạn code Application.WorksheetFunction.Vlookup(...). Hàm vlookup này hoàn toàn giống kết cấu trong excel. Chỉ có điều, các địa chỉ tham chiếu hơi khác tí là bạn phải gọi cụ thể vùng tham chiếu bằng VBA. Ví dụ nhé: Application.WorksheetFuntion.Vlookup(Sheet2.Range("A1").Value, Sheet1.Range("A1:B50"),2,0)).Em muốn thực hiện phương pháp thứ 2 tức:"Thực hiện trực tiếp công thức trên code, khi gán giá trị xuống sheet, thì chỉ là kết quả được tính toán."
Cũng nói thêm, khi bạn sử dụng nhiều Hàm của Excel hoặc một hàm lặp đi lặp lại, thì bạn nên chọn một biến thay thế cho nó ngắn gọn, ví dụ:Bạn dùng đoạn code Application.WorksheetFunction.Vlookup(...). Hàm vlookup này hoàn toàn giống kết cấu trong excel. Chỉ có điều, các địa chỉ tham chiếu hơi khác tí là bạn phải gọi cụ thể vùng tham chiếu bằng VBA. Ví dụ nhé: Application.WorksheetFuntion.Vlookup(Sheet2.Range("A1").Value, Sheet1.Range("A1:B50"),2,0)).
Sub Test()
Dim Ham As WorksheetFunction
Set Ham = WorksheetFunction
Sheet2.Range("D1") = Ham.VLookup(Sheet2.Range("A1").Value, Sheet1.Range("A1:B50"), 2, 0)
End Sub
Cũng nói thêm, khi bạn sử dụng nhiều Hàm của Excel hoặc một hàm lặp đi lặp lại, thì bạn nên chọn một biến thay thế cho nó ngắn gọn, ví dụ:
Mã:Sub Test() Dim Ham As WorksheetFunction Set Ham = WorksheetFunction Sheet2.Range("D1") = Ham.VLookup(Sheet2.Range("A1").Value, Sheet1.Range("A1:B50"), 2, 0) End Sub
Ngoài ra khi bạn làm như trên, thì sau khi bạn gõ chữ Ham thì bạn chỉ cần đặt dấu chấm (.) sau nó, một danh sách hàm có thể sử dụng trong VBA được hiện ra, bạn chỉ việc chọn hàm nào cần thiết mà thực thi cấu trúc của nó.
Em nhờ mọi cả nhà giúp em viết code chuyển từ hàm Vlookup() sang Code VBA
Vậy thì bạn cứ thực hiện trên trang tính cho tươm tất rồi đối chiếu với các hàm của các bài trên mà chỉnh sửa cho vừa í.Em có nhu cầu muốn tìm kiếm thêm 1 cột nữa, tìm giá trị trên cột B
Vâng. file thế này anh. xin giúp em.Hoặc là bạn cho file lên đây để mọi người làm trực tiếp vào file của bạn
Hoặc là tham khảo bài này:
http://www.giaiphapexcel.com/forum/...ết-dùng-mã-vba-thay-thế-cho-hàm-vlookup/page3
Vâng. file thế này anh. xin giúp em.
Thầy ơi! Cho em hỏi thêm chút...Để đở mất công những người trợ giúp, khuyên các bạn nên đưa file thật (hoặc có cấu trúc giống với file thật) lên đây
Rút kinh nghiệm nhiều lần rồi: Các bạn cứ gửi lên đây file giả lập "tào lao", khi người ta viết code xong, không biết cách áp dụng vào file thật lại hỏi tới hỏi lui
Sheet2.Range("C1") = Ham.VLookup(Sheet2.Range("$B1").Value, Sheet1.Range("B1:C5"), 2, 0)
Thầy ơi! Cho em hỏi thêm chút...Viết lại đoạn code trên sao để có kết quả từ C2:C5 ( Em chỉ làm được kết quả tại ô C1)Mã:Sheet2.Range("C1") = Ham.VLookup(Sheet2.Range("$B1").Value, Sheet1.Range("B1:C5"), 2, 0)
Sub Test()
Dim Ham As WorksheetFunction
Set Ham = WorksheetFunction
For i = 1 To 5
Sheet2.Range("C" & i) = Ham.VLookup(Sheet2.Range("$B" & i).Value, Sheet1.Range("B1:C5"), 2, 0)
Next
End Sub
Xin thưa anh là: Kết quả dò tìm đó lại được Copy đi nơi khác hoặc Sheet khác, nên nếu để công thức sẽ hay bị sai, do đó cần macro để lấy giá trị anh ạ.sao ko xài vlookup đi mà phải viết code?
nếu viết code thì xài code luôn sao phải xài worksheetfunction?
Sheet2.Range("C1:C5") = Ham.VLookup(Sheet2.Range("B1:B5").Value, Sheet1.Range("B1:C5"), 2, 0)
Dạ, cấu trúc file thật của em đây.
Code này của anh Hoàng Trọng Nghĩa viết mới tìm 1 cột em muốn tìm thêm 1 cột nữa.
Sub Test()
Dim Ham As WorksheetFunction
Set Ham = WorksheetFunction
Sheet2.Range("D1") = Ham.VLookup(Sheet2.Range("A1").Value, Sheet1.Range("A1:B50"), 2, 0)
End Sub
Public Chk As Boolean, Dic As Object, aResult()
Sub Auto_Open()
Dim wks As Worksheet, SrcRng As Range, sArray
Dim lR As Long, i As Long, n As Long, tmp
On Error Resume Next
Set wks = Sheets("Sheet2")
Set SrcRng = wks.Range("A2:C10000")
sArray = SrcRng.Value
ReDim aResult(1 To UBound(sArray, 1), 1 To UBound(sArray, 2))
Set Dic = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(sArray, 1)
If CStr(sArray(i, 1)) <> "" Then
tmp = sArray(i, 1)
If Not Dic.Exists(tmp) Then
lR = lR + 1
Dic.Add tmp, lR
aResult(lR, 1) = tmp
aResult(lR, 2) = sArray(i, 2)
aResult(lR, 3) = sArray(i, 3)
End If
End If
Next
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Chk = True
End Sub
Private Sub Worksheet_Deactivate()
If Chk Then
Auto_Open
Chk = False
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rTarget As Range, aTarget, i As Long
Dim arr(), tmp
On Error Resume Next
If Dic Is Nothing Then Auto_Open
If Not Intersect(Range("B3:B1000"), Target) Is Nothing Then
Set rTarget = Intersect(Range("B3:B1000"), Target)
If IsArray(rTarget.Value) Then
aTarget = rTarget.Value
Else
ReDim aTarget(1 To 1, 1 To 1)
aTarget(1, 1) = rTarget.Value
End If
ReDim arr(1 To UBound(aTarget, 1), 1 To 2)
For i = 1 To UBound(aTarget, 1)
If aTarget(i, 1) <> "" Then
tmp = aTarget(i, 1)
If Dic.Exists(tmp) Then
arr(i, 1) = aResult(Dic.Item(tmp), 2)
arr(i, 2) = aResult(Dic.Item(tmp), 3)
End If
End If
Next
rTarget.Offset(, 1).Resize(, 2).Value = arr
End If
End Sub
Cám Ơn anh Em đã hiểu.. (phải thêm For nữa)sao ko xài vlookup đi mà phải viết code?
nếu viết code thì xài code luôn sao phải xài worksheetfunction?
Mã:Sub Test() Dim Ham As WorksheetFunction Set Ham = WorksheetFunction For i = 1 To 5 Sheet2.Range("C" & i) = Ham.VLookup(Sheet2.Range("$B" & i).Value, Sheet1.Range("B1:C5"), 2, 0) Next End Sub
Xin thưa anh là: Kết quả dò tìm đó lại được Copy đi nơi khác hoặc Sheet khác, nên nếu để công thức sẽ hay bị sai, do đó cần macro để lấy giá trị anh ạ.
...
chỉ góp ý vậy thôi, tùy ý thích của mỗi người mà..........hihihihih
Sheet2.Range("C1:C5") = Ham.VLookup(Sheet2.Range("B1:B5").Value, Sheet1.Range("B1:C5"), 2, 0)
Dạ, cấu trúc file thật của em đây.
Code này của anh Hoàng Trọng Nghĩa viết mới tìm 1 cột em muốn tìm thêm 1 cột nữa.
Sub Test()
Dim Ham As WorksheetFunction
Set Ham = WorksheetFunction
Sheet2.Range("D1") = Ham.VLookup(Sheet2.Range("A1").Value, Sheet1.Range("A1:B50"), 2, 0)
End Sub
Sub Find()
Dim i&, LookUp(), KQ(), Rng As Range
LookUp = Range(Sheet3.[B3], Sheet3.[B65000].End(3))
ReDim KQ(1 To UBound(LookUp), 1 To 2)
For i = 1 To UBound(LookUp)
Set Rng = Sheet2.[A1:A65000].Find(LookUp(i, 1), , , 1)
If Not Rng Is Nothing Then
KQ(i, 1) = Rng(, 2)
KQ(i, 2) = Rng(, 3)
End If
Next
Sheet3.[C3].Resize(i - 1, 2) = KQ
End Sub
sẳn đề tài này, góp một ý như sau:
anh em viết cho một đoạn code vlookup có giá trị trùng.
cho dữ liệu nhiều nhiều mọt chút, ví dụ 10,20 ngàn dòng
Cảm ơn anh ạ. Code chạy tốt, còn vấn đề trùng không cần bàn anh ạ. Dữ liệu đầu sẽ không có trùng anh.Thử với code này xem sao:
Chỉ có điều là trường hợp nhiều tên trùng nhau thì sao ta? với code này chỉ tìm được dòng đầu tiên thôi nha.
Tôi chưa hiểu ý bạn lắm, dù trùng thì vlookup vẫn ra kết quả là dòng đầu tiên tìm thấy, hay bạn muốn nó lấy kết quả ở dòng cuối cùng?
lấy giá trị kế tiếp chứ
ví dụ bảng do
a1 --- 1
a2 --- 2
a1 --- 3
a1 --- 4
thì kết quả dò trả về theo thứ tự trên
a1 ---1
a1 ---3
a1 ---4
tức là để áp ụp trong trường hợp không thể áp dụng vlookup đó
cám ơn
Có phải bạn muốn Filter những giá trị a1?lấy giá trị kế tiếp chứ
ví dụ bảng do
a1 --- 1
a2 --- 2
a1 --- 3
a1 --- 4
thì kết quả dò trả về theo thứ tự trên
a1 ---1
a1 ---3
a1 ---4
tức là để áp ụp trong trường hợp không thể áp dụng vlookup đó
cám ơn
Em cũng đang mong code cho bài dạng này. Lót dép ngồi hóng ^^lấy giá trị kế tiếp chứ
ví dụ bảng do
a1 --- 1
a2 --- 2
a1 --- 3
a1 --- 4
thì kết quả dò trả về theo thứ tự trên
a1 ---1
a1 ---3
a1 ---4
tức là để áp ụp trong trường hợp không thể áp dụng vlookup đó
cám ơn
Bạn cho file giả lập trên xem thử (với bảng dò chừng 20 dòng là được)
thực ra thì dự đ5nh để anh em mới dzọc code tập chơi, sư phụ nhả vô thì hết đề tài nói rồi........hhiihihihihih
anh em mới học code làm thử
cám ơn
thực ra thì dự đ5nh để anh em mới dzọc code tập chơi, sư phụ nhả vô thì hết đề tài nói rồi........hhiihihihihih
anh em mới học code làm thử
cám ơn
Không phải là không hứng thú, mà là đề bài này không thực tế, nếu bố trí dữ liệu mà trùng nhau như vậy thì làm cho vui thôi
Em thấy chủ đề này cũng hay thế cơ mà. Thực tế thì phải tùy người tùy yêu cầu công việc. Ai thấy không thực tế, không hứng thú thì có thể đọc rồi bỏ qua. Còn xóa thì nghĩ chắc là không cần thiết. Với những người trình độ "gà vịt" như em thì vẫn muốn học mà.
thôi thì nhờ mod nào đi ngang qua xóa dùm các bài này
cám ơn
lấy giá trị kế tiếp chứ
ví dụ bảng do
a1 --- 1
a2 --- 2
a1 --- 3
a1 --- 4
thì kết quả dò trả về theo thứ tự trên
a1 ---1
a1 ---3
a1 ---4
tức là để áp ụp trong trường hợp không thể áp dụng vlookup đó
cám ơn
người hỏi không nói trường hợp nếu gọi đến a1 lần thứ >4 thì trả về giá trị nào ? vẫn là a1---4 hay quay ngược về a1---1
giải quyết cho a1---4 khi gọi đến a1 lần thứ >4
Tôi nghĩ kết quả trả về là lỗi N/A mới đúng
Thêm nữa: Dùng End(xlDown) nguy hiểm quá! Xóa vùng F2:F11 thì code chạy... "mút chỉ" luôn. Còn xóa cell nào đó ở giữa thì.. Ẹc... Ẹc...
(Khi viết code, tôi ghét nhất là thằng End(...)... cứ chọn vùng dữ liệu dư ra một chút là được rồi)
------------------------------
Các bạn thử viết thành 1 Function xem sao (thay vì Sub)
giá trị có nhìn thấy trên bảng lý do gì trả về N/A vậy thầy ?
người hỏi cũng phải có người trả lời mới sinh động chứ sao lại xóa ?
người hỏi không nói trường hợp nếu gọi đến a1 lần thứ >4 thì trả về giá trị nào ? vẫn là a1---4 hay quay ngược về a1---1
giải quyết cho a1---4 khi gọi đến a1 lần thứ >4
Public Function FLOOKUP(TriDo As Variant, BangDo As Range, Cot As Long, Lan As Long) As String
Dim i As Long, k As Long, Tam()
For i = 1 To BangDo.Rows.Count
If TriDo = BangDo(i, 1).Value Then
k = k + 1
ReDim Preserve Tam(1 To k)
Tam(k) = BangDo(i, Cot).Value
End If
Next i
If Lan > 0 And Lan <= k Then FLOOKUP = Tam(Lan)
End Function
Xin góp một bài, code chưa bẫy lỗi, hehehe!
Mã:
người hỏi cũng phải có người trả lời mới sinh động chứ sao lại xóa ?
người hỏi không nói trường hợp nếu gọi đến a1 lần thứ >4 thì trả về giá trị nào ? vẫn là a1---4 hay quay ngược về a1---1
giải quyết cho a1---4 khi gọi đến a1 lần thứ >4
dic(tempKey)(r) = sArr(r, 2)
Sub VlookupMultipleValue()
Dim ng, dich, tam As Variant, i, j, k As Long, Dng, Ddich As Object
ng = [a2].Resize([a60000].End(3).Row, 2)
dich = [f2].Resize([f60000].End(3).Row, 2)
Set Dng = CreateObject("Scripting.Dictionary")
Set Ddich = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(ng)
If Not Dng.Exists(ng(i, 1)) Then
Dng.Add ng(i, 1), ng(i, 2)
Else
Dng.Item(ng(i, 1)) = Dng.Item(ng(i, 1)) & "," & ng(i, 2)
End If
Next
For i = 1 To UBound(dich)
If Dng.Exists(dich(i, 1)) Then
If Not Ddich.Exists(dich(i, 1)) Then
Ddich.Add dich(i, 1), 0
Else
Ddich.Item(dich(i, 1)) = Ddich.Item(dich(i, 1)) + 1
End If
tam = Split(Dng.Item(dich(i, 1)), ",")
For j = 0 To UBound(tam)
If j = Ddich.Item(dich(i, 1)) Then dich(i, 2) = tam(j): Exit For
Next
End If
Next
[f2].Resize([f60000].End(3).Row, 2) = dich
End Sub
à, tôi thấy bạn sử dụng 2 cái dic rồi....heheheh
tôi hơi bị bối rối bởi đoạn code
tôi ko biết nó là key hay item???Mã:dic(tempKey)(r) = sArr(r, 2)
==============
góp thêm với bạn một cách tôi làm bằng dic
chúc vui vẻMã:Sub VlookupMultipleValue() Dim ng, dich, tam As Variant, i, j, k As Long, Dng, Ddich As Object ng = [a2].Resize([a60000].End(3).Row, 2) dich = [f2].Resize([f60000].End(3).Row, 2) Set Dng = CreateObject("Scripting.Dictionary") Set Ddich = CreateObject("Scripting.Dictionary") For i = 1 To UBound(ng) If Not Dng.Exists(ng(i, 1)) Then Dng.Add ng(i, 1), ng(i, 2) Else Dng.Item(ng(i, 1)) = Dng.Item(ng(i, 1)) & "," & ng(i, 2) End If Next For i = 1 To UBound(dich) If Dng.Exists(dich(i, 1)) Then If Not Ddich.Exists(dich(i, 1)) Then Ddich.Add dich(i, 1), 0 Else Ddich.Item(dich(i, 1)) = Ddich.Item(dich(i, 1)) + 1 End If tam = Split(Dng.Item(dich(i, 1)), ",") For j = 0 To UBound(tam) If j = Ddich.Item(dich(i, 1)) Then dich(i, 2) = tam(j): Exit For Next End If Next [f2].Resize([f60000].End(3).Row, 2) = dich End Sub
For j = 0 To UBound(tam)
If j = Ddich.Item(dich(i, 1)) Then dich(i, 2) = tam(j): Exit For
Next
bạn nói thế là bạn chưa hiểu đoạn code của t . t cũng ko cần ai hiểu code của mình , đối với t miễn sao bấm nút có chạy là được
ta không bàn đến những lỗi lặt vặt . ta chỉ nói đến ý tưởng
code của t dùng rất nhiều dictionary , mỗi item của dic cha lại là 1 dictionary con bởi vì t không biết liệu dữ liệu cần dò là số hay chuỗi (như ở #44 đã nêu chẳng hạn )
nếu chắc chắn dữ liệu cần dò là numeric thì có thể xài nối chuỗi bằng "," như bạn
nếu bạn hiểu code của t thì bạn sẽ rút kinh nghiệm cho code của bạn chỉ cần sử dụng 1 dictionary duy nhất mà thôi ( nghĩ xem có thể ko ?)
và việc truy lấy giá trị của item trong mảng khi đã biết index kể cả là index đó vượt ra ngoài ubound mà phải xài lặp for lại càng khó coi
Mã:For j = 0 To UBound(tam) If j = Ddich.Item(dich(i, 1)) Then dich(i, 2) = tam(j): Exit For Next
tất nhiên không ai có quyền bắt bạn code thế này , code thế nọ , chúng ta chỉ góp ý xây dưng nhau mà thôi
và việc truy lấy giá trị của item trong mảng khi đã biết index kể cả là index đó vượt ra ngoài ubound mà phải xài lặp for lại càng khó coi
Mã:For j = 0 To UBound(tam) If j = Ddich.Item(dich(i, 1)) Then dich(i, 2) = tam(j): Exit For Next
Sub VlookupMultipleValue()
Dim ng, dich, tam As Variant, i, j, k As Long, Dng, Ddich As Object
[g2:g60000].Clear
ng = [a2].Resize([a60000].End(3).Row, 2)
dich = [f2].Resize([f60000].End(3).Row, 2)
Set Dng = CreateObject("Scripting.Dictionary")
Set Ddich = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(ng)
If Not Dng.Exists(ng(i, 1)) Then
Dng.Add ng(i, 1), ng(i, 2)
Else
Dng.Item(ng(i, 1)) = Dng.Item(ng(i, 1)) & "#" & ng(i, 2)
End If
Next
For i = 1 To UBound(dich)
If Dng.Exists(dich(i, 1)) Then
If Not Ddich.Exists(dich(i, 1)) Then
Ddich.Add dich(i, 1), 0
Else
Ddich.Item(dich(i, 1)) = Ddich.Item(dich(i, 1)) + 1
End If
tam = Split(Dng.Item(dich(i, 1)), "#")
k = Ddich.Item(dich(i, 1))
If k <= UBound(tam) Then dich(i, 2) = tam(k)
End If
Next
[f2].Resize([f60000].End(3).Row, 2) = dich
End Sub
Bài này có thể dùng 1 Dic, 2 vòng lặp, 1 mảng gán kết quả
nếu bạn hiểu code của t thì bạn sẽ rút kinh nghiệm cho code của bạn chỉ cần sử dụng 1 dictionary duy nhất mà thôi ( nghĩ xem có thể ko ?)
thư giãn nào có gì căng thếtôi nghĩ là nếu làm được như vậy thì phải làm sao mà một key add được nhiều items
Thật tình thì bài này cũng bình thường thôi mà, có thể bạn nghĩ hơi.....cao cao nên nó "ừ ứ ư". Mình cứ "phang" kiểu "giang hồ GPE" thì thế này:đang chờ bác cho xem code
tôi nghĩ là nếu làm được như vậy thì phải làm sao mà một key add được nhiều items
suy nghĩ 2 ngày rồi vẫn chưa ra............hichic
Public Sub MotDitto()
Dim Vung, Tim, d, I, Kq
Set d = CreateObject("scripting.dictionary")
Vung = Range([A2], [A50000].End(xlUp)).Resize(, 2)
Tim = Range([F2], [F50000].End(xlUp))
For I = 1 To UBound(Vung)
If Not d.exists(Vung(I, 1)) Then
d.Add Vung(I, 1), Vung(I, 2) & " "
Else
d.Item(Vung(I, 1)) = d.Item(Vung(I, 1)) & Vung(I, 2) & " "
End If
Next I
ReDim Kq(1 To UBound(Tim), 1 To 1)
For I = 1 To UBound(Tim)
If d.exists(Tim(I, 1)) Then
If Len(d.Item(Tim(I, 1))) Then
Kq(I, 1) = Left(d.Item(Tim(I, 1)), InStr(d.Item(Tim(I, 1)), " "))
d.Item(Tim(I, 1)) = Replace(d.Item(Tim(I, 1)), Kq(I, 1), "")
End If
End If
Next I
[H2].Resize(UBound(Tim)) = Kq
End Sub
Thật tình thì bài này cũng bình thường thôi mà, có thể bạn nghĩ hơi.....cao cao nên nó "ừ ứ ư". Mình cứ "phang" kiểu "giang hồ GPE" thì thế này:
1) Chạy dữ liệu "nguồn" (tạm gọi như thế) nạp dữ liệu vào em Đít-to
2) Chạy dữ liệu "đích" (cũng....tạm gọi như thế) lôi lại dữ liệu đã nạp vào em Đít-to gán vào mảng kết quả, phang xuống sheet là....xong
Đại khái thế này ( làm theo dữ liệu trong bài của bạn, nếu có khác đi thì tùy tình hình mà sửa cho phù hợp)
Híc, thânMã:Public Sub MotDitto() Dim Vung, Tim, d, I, Kq Set d = CreateObject("scripting.dictionary") Vung = Range([A2], [A50000].End(xlUp)).Resize(, 2) Tim = Range([F2], [F50000].End(xlUp)) For I = 1 To UBound(Vung) If Not d.exists(Vung(I, 1)) Then d.Add Vung(I, 1), Vung(I, 2) & " " Else d.Item(Vung(I, 1)) = d.Item(Vung(I, 1)) & Vung(I, 2) & " " End If Next I ReDim Kq(1 To UBound(Tim), 1 To 1) For I = 1 To UBound(Tim) If d.exists(Tim(I, 1)) Then If Len(d.Item(Tim(I, 1))) Then Kq(I, 1) = Left(d.Item(Tim(I, 1)), InStr(d.Item(Tim(I, 1)), " ")) d.Item(Tim(I, 1)) = Replace(d.Item(Tim(I, 1)), Kq(I, 1), "") End If End If Next I [H2].Resize(UBound(Tim)) = Kq End Sub
Hihi, thì đã bảoAnh Cò thử sửa cell B5=20 rồi chạy code xem thế nào?
Ẹc... Ẹc...
Chưa ok thì .....sửa tí tẹo ( do cách lấy dữ liệu trong Item ra thôi mà. Híc)....làm theo dữ liệu trong bài của bạn,....
Public Sub MotDitto()
Dim Vung, Tim, d, I, Kq
Set d = CreateObject("scripting.dictionary")
Vung = Range([A2], [A50000].End(xlUp)).Resize(, 2)
Tim = Range([F2], [F50000].End(xlUp))
For I = 1 To UBound(Vung)
If Not d.exists(Vung(I, 1)) Then
d.Add Vung(I, 1), Vung(I, 2) & " "
Else
d.Item(Vung(I, 1)) = d.Item(Vung(I, 1)) & Vung(I, 2) & " "
End If
Next I
ReDim Kq(1 To UBound(Tim), 1 To 1)
For I = 1 To UBound(Tim)
If d.exists(Tim(I, 1)) Then
If Len(d.Item(Tim(I, 1))) Then
Kq(I, 1) = Left(d.Item(Tim(I, 1)), InStr(d.Item(Tim(I, 1)), " "))
[I][B]d.Item(Tim(I, 1)) = Right(d.Item(Tim(I, 1)), Len(d.Item(Tim(I, 1))) - Len(Kq(I, 1)))[/B][/I]
End If
End If
Next I
[H2].Resize(UBound(Tim)) = Kq
End Sub
Sub NoneDic()
Dim Vung, Tim, Tm, i, j
Vung = Range([A2], [A50000].End(xlUp)).Resize(, 2)
Tim = Range([F2], [F50000].End(xlUp)).Resize(, 2)
Tm = Range([A2], [A50000].End(xlUp))
On Error Resume Next
For i = 1 To UBound(Tim, 1)
j = WorksheetFunction.Match(Tim(i, 1), Tm, 0)
If Err.Number > 0 Then
Tim(i, 2) = ""
Err.Clear
Else
Tim(i, 2) = Vung(j, 2)
Vung(j, 1) = ""
End If
Next
Range([F2], [F50000].End(xlUp)).Resize(, 2) = Tim
End Sub
Mình cũng góp 1 bài không dùng Dic
Mã:... On Error Resume Next For i = 1 To UBound(Tim, 1) j = WorksheetFunction.Match(Tim(i, 1), Tm, 0) If Err.Number > 0 Then ...
Nếu bạn dùng hàm Match thì gọi nó trong ngữ cảnh Application, như vậy khỏi phải bẫy lỗi.
j = Application.Match(Tim(i, 1), Tm, 0)
If isnumeric(j) Then
(ở đây là vì trong code của bạn dim j là mặc định, tức là variant. Nếu code của bạn dim j là integer thì bắt buộc phải bẫy lỗi)
Sub MyVlookup()
Dim arr1(), arr2(), i&, j&
j = Range("B65000").End(xlUp).Row
Range("C2") = 1
Range("C2").AutoFill Range("C2:C" & j), xlFillSeries
Range("A2:C" & j).Sort Range("A2")
arr1 = Range("A2:B" & j)
Range("A2:C" & j).Sort Range("C2")
Range("C2:C" & j).Clear
j = Range("F65000").End(xlUp).Row
Range("E2") = 1
Range("E2").AutoFill Range("E2:E" & j), xlFillSeries
Range("E2:F" & j).Sort Range("F2")
arr2 = Range("F2:G" & Range("F65000").End(xlUp).Row)
For j = 1 To UBound(arr2)
If i > UBound(arr1) - 1 Then
arr2(j, 2) = ""
Else
Do While i <= UBound(arr1) - 1
i = i + 1
If arr1(i, 1) = arr2(j, 1) Then
arr2(j, 2) = arr1(i, 2)
Exit Do
ElseIf arr1(i, 1) > arr2(j, 1) Then
arr2(j, 2) = ""
i = i - 1
Exit Do
End If
Loop
End If
Next
Range("F2:G" & j) = arr2
Range("E2:G" & j).Sort Range("E2")
Range("E2:E" & j).Clear
End Sub
Sub NoneDic()
Dim Vung, Tim, Tm, I, J
Vung = Range([A2], [A50000].End(xlUp)).Resize(, 2)
Tim = Range([F2], [F50000].End(xlUp)).Resize(, 2)
Tm = Range([A2], [A50000].End(xlUp))
On Error Resume Next
For I = 1 To UBound(Tim, 1)
J = WorksheetFunction.Match(Tim(I, 1), Tm, 0)
If J > 0 Then Tim(I, 2) = Vung(J, 2): Tm(J, 1) = "": J = ""
Next
Range([F2], [F50000].End(xlUp)).Resize(, 2) = Tim
End Sub
Code của bác Sealand không khác gì vlookup thông thường cả, tức là chỉ tìm giá trị đầu tiên. Ở đây đề bài mà bác Let Gâu là sau khi tìm được "Nguyễn Văn 12" lần 1 ở hàng 2 (kết quả 20) rồi thì lần 2 sẽ tìm từ hàng sau trở đi (kết quả ở hàng 5 là 28). Nếu không tìm thấy thì để trống.
Sub NoneDic()
Dim Vung, Tim, Tm, i, j
Vung = Range([A2], [A50000].End(xlUp)).Resize(, 2)
Tim = Range([F2], [F50000].End(xlUp)).Resize(, 2)
Tm = Range([A2], [A50000].End(xlUp))
On Error Resume Next
For i = 1 To UBound(Tim, 1)
j = WorksheetFunction.Match(Tim(i, 1), Tm, 0)
If Err.Number > 0 Then
Tim(i, 2) = ""
Err.Clear
Else
Tim(i, 2) = Vung(j, 2)
[COLOR=#ff0000]Vung(j, 1) = ""[/COLOR]
End If
Next
Range([F2], [F50000].End(xlUp)).Resize(, 2) = Tim
End Sub
Tôi hiểu giải thuật của anh Sealand
Mấu chốt nằm ở chỗ màu đỏ ấyMã:Sub NoneDic() Dim Vung, Tim, Tm, i, j Vung = Range([A2], [A50000].End(xlUp)).Resize(, 2) Tim = Range([F2], [F50000].End(xlUp)).Resize(, 2) Tm = Range([A2], [A50000].End(xlUp)) On Error Resume Next For i = 1 To UBound(Tim, 1) j = WorksheetFunction.Match(Tim(i, 1), Tm, 0) If Err.Number > 0 Then Tim(i, 2) = "" Err.Clear Else Tim(i, 2) = Vung(j, 2) [COLOR=#ff0000]Vung(j, 1) = ""[/COLOR] End If Next Range([F2], [F50000].End(xlUp)).Resize(, 2) = Tim End Sub
Có thể anh Sealand viết nhầm, lý ra phải là Tm(j, 1) = "" mới đúng
Nếu gọi nó trong ngữ cảnh Application thì đối tượng Application sẽ kềm hiện tượng lỗi lại và đưa luôn cái Object lỗi này cho Match. Vì vậy ta không cần bẫy lỗi. Trong trường hợp này ta xét thẳng tính chất của đối tượng do hàm Match trả về, nếu nó không phải là một con số thì kết luận là tìm không được.
TypeName(Application.Match("a",Range("A1:A10"),0))
Vừa thử xong:
Nếu kết quả trả về là "Error" thì có nghĩa là không tìm thấyMã:TypeName(Application.Match("a",Range("A1:A10"),0))
-------------------
Sao chưa thấy ai dùng Find Method nhỉ?
{=IF(ISERROR(MATCH(F2,$A$2:$A$12,0)),"not found in tb",IF(COUNTIF($F$2:F2,F2)>COUNTIF($A$2:$A$12,F2),"out side",INDEX($A$2:$B$12,SMALL(IF($A$2:$A$12=F2,ROW($A$2:$A$12)),COUNTIF($F$2:F2,F2))[B][SIZE=4]-1[/SIZE][/B],2)))}
Góp vui thêm công thức có thông báo:bới lên cái nữa
đã muộn nhưng có vẫn vui
xin được góp vui 1 cách dùng hàm excel
công thức tại ô H2
với số -1 còn tùy vào việc đặt bảng dò ở đâu . ví dụ bảng dò bắt đầu từ dòng số 10 thì phải -9Mã:{=IF(ISERROR(MATCH(F2,$A$2:$A$12,0)),"not found in tb",IF(COUNTIF($F$2:F2,F2)>COUNTIF($A$2:$A$12,F2),"out side",INDEX($A$2:$B$12,SMALL(IF($A$2:$A$12=F2,ROW($A$2:$A$12)),COUNTIF($F$2:F2,F2))[B][SIZE=4]-1[/SIZE][/B],2)))}
{=IF(COUNTIF($A$2:$A$12,F2)=0,"not found in tb",IFERROR(INDEX($B$2:$B$12,SMALL(IF($A$2:$A$12=F2,ROW($A$2:$A$12)-1,""),COUNTIF($F$2:F2,F2))),"out side"))}
{=IFERROR(INDEX($B$2:$B$12,SMALL(IF($A$2:$A$12=F2,ROW($A$2:$A$12)-1,""),COUNTIF($F$2:F2,F2))),"")}
Vẫn áp dụng bài này:
http://www.giaiphapexcel.com/forum/...ết-dùng-mã-vba-thay-thế-cho-hàm-vlookup/page3
Ta làm như sau:
1> Code trong module
2> Code trong sheet2Mã:Public Chk As Boolean, Dic As Object, aResult() Sub Auto_Open() Dim wks As Worksheet, SrcRng As Range, sArray Dim lR As Long, i As Long, n As Long, tmp On Error Resume Next Set wks = Sheets("Sheet2") Set SrcRng = wks.Range("A2:C10000") sArray = SrcRng.Value ReDim aResult(1 To UBound(sArray, 1), 1 To UBound(sArray, 2)) Set Dic = CreateObject("Scripting.Dictionary") For i = 1 To UBound(sArray, 1) If CStr(sArray(i, 1)) <> "" Then tmp = sArray(i, 1) If Not Dic.Exists(tmp) Then lR = lR + 1 Dic.Add tmp, lR aResult(lR, 1) = tmp aResult(lR, 2) = sArray(i, 2) aResult(lR, 3) = sArray(i, 3) End If End If Next End Sub
3> Code cho sheet 3Mã:Private Sub Worksheet_Change(ByVal Target As Range) Chk = True End Sub Private Sub Worksheet_Deactivate() If Chk Then Auto_Open Chk = False End If End Sub
Mã:Private Sub Worksheet_Change(ByVal Target As Range) Dim rTarget As Range, aTarget, i As Long Dim arr(), tmp On Error Resume Next If Dic Is Nothing Then Auto_Open If Not Intersect(Range("B3:B1000"), Target) Is Nothing Then Set rTarget = Intersect(Range("B3:B1000"), Target) If IsArray(rTarget.Value) Then aTarget = rTarget.Value Else ReDim aTarget(1 To 1, 1 To 1) aTarget(1, 1) = rTarget.Value End If ReDim arr(1 To UBound(aTarget, 1), 1 To 2) For i = 1 To UBound(aTarget, 1) If aTarget(i, 1) <> "" Then tmp = aTarget(i, 1) If Dic.Exists(tmp) Then arr(i, 1) = aResult(Dic.Item(tmp), 2) arr(i, 2) = aResult(Dic.Item(tmp), 3) End If End If Next rTarget.Offset(, 1).Resize(, 2).Value = arr End If End Sub
Tốt nhất bạn nên mở topic mới kèm file + kết quả mong muốn lên.các bác cho hỏi luôn làm cách nào để tự động them code cho sheet3, vì sheet3 của mình do PM xuất, không có code sẵn, chỉ có giá trị ở cột B, còn lại phải vlookup từ 1 sheet danh mục như sheet 2
1. Click ButtonKính nhờ các cao nhân trợ giúp. Mong muốn của em là thay vì dùng hàm Vlookup không thể Ctrl [ để đến cell đang liên kết trực tiếp giá trị và hàm Vlookup cũng làm nặng file rất nhiều. Em làm bên xây dựng, việc lập giá dự toán, dự thầu sẽ dùng rất nhiều đến tính năng này. Cụ thể em đã có 1 file tổng hợp các vật tư cần dùng bao gồm có cột mã vật tư, tên vật tư, đơn vị tính và giá vật tư hiện tại. 1 file đích thì đang cần nối giá vật tư hiện tại vào cũng có các cột tương tự là MSVT, tên vật tư, đơn vị tính và cột giá cần nối đến.
Trân trọng cảm ơn mọi người đã quan tâm.
Em cảm ơn Anh nhiều. Nếu có giữ được link = trực tiếp từ file nguồn để bấm Ctrl [ sẽ đến được địa chỉ đang link thì tròn bài Anh ạ. Việc đổ ra giá trị (số chết) này nhanh hơn dùng hàm Vlookup nhưng click vào hàm Vlookup ít ra vẫn biết được giá trị lấy từ đâu. Em được voi đòi luôn cả bà tưng nữa Anh thông cảm nhé. Trân trọng.1. Click Button
2. Chọn đến File nguồn "0. Gia vat tu.xlsx"
Có rủi ro là chọn không đúng file thì sẽ không ra kết quả gì.
Theo tôi, bạn nên copy các code mã vật tư và 1 sheet, từ đó tìm kiếm bằng phương thức Find là nhanh nhất. Thực chất thì code của tôi cũng là copy bảng MSVT vào file gốc, rồi tìm kiếm trên đó thôi.
[gpecode=vb]
Sub FindMethod()
Dim FileName As String, sArr(), i&, MSVT(), KQ1(), KQ2(), Rng As Range
If Not Application.FindFile Then Exit Sub
With ActiveWorkbook
FileName = .Name
With .ActiveSheet
sArr = .Range(.[B4], .[E65000].End(3)).Value
End With
.Close False
End With
Sheets("TH vat tu XD").[AA1].Resize(UBound(sArr), 4) = sArr
MSVT = Range(Sheets("TH vat tu XD").[B8], Sheets("TH vat tu XD").[B65000].End(3))
ReDim KQ1(1 To UBound(MSVT), 1 To 2)
ReDim KQ2(1 To UBound(MSVT), 1 To 1)
For i = 1 To UBound(MSVT)
Set Rng = Sheets("TH vat tu XD").[AA1:AA50000].Find(MSVT(i, 1), , , 1)
If Not Rng Is Nothing Then
KQ1(i, 1) = Rng(, 2)
KQ1(i, 2) = Rng(, 3)
KQ2(i, 1) = Rng(, 4)
End If
Next
Sheets("TH vat tu XD").[C8].Resize(i - 1, 2) = KQ1
Sheets("TH vat tu XD").[G8].Resize(i - 1, 1) = KQ2
Sheets("TH vat tu XD").[AA1].Resize(UBound(sArr), 4).Clear
Erase sArr
End Sub[/gpecode]
[note]Lần sau bạn nên mở 1 Topic mới để đặt câu hỏi, đừng chèn câu hỏi vào topic của người khác[/note]
Tôi cũng chưa hiểu thao tác ctrl [ là để làm j nữa.Em cảm ơn Anh nhiều. Nếu có giữ được link = trực tiếp từ file nguồn để bấm Ctrl [ sẽ đến được địa chỉ đang link thì tròn bài Anh ạ. Việc đổ ra giá trị (số chết) này nhanh hơn dùng hàm Vlookup nhưng click vào hàm Vlookup ít ra vẫn biết được giá trị lấy từ đâu. Em được voi đòi luôn cả bà tưng nữa Anh thông cảm nhé. Trân trọng.
Tôi cũng chưa hiểu thao tác ctrl [ là để làm j nữa.
Những để lấy tên file và đường dẫn của file nguồn dán kết quả vào 1 ô nào đó để biết đó là file nào thì có đúng ý bạn không?
Sao không ném luôn cái file giá vật tư vào file Nha de xe đi bạn!!! Làm như thế có phải đỡ tốn công hơn không. Muốn link trực tiếp viết code cũng được, mà chả cần code kiếc gì, viết hàm kết hợp thủ thuật là có liên kết trực tiếp thôi. Còn cái sheet vật tư trong Nhà để xe thì liên kết với File giá vật tư, trong trường hợp nhiều file dự toán cùng liên kết đến 1 giá vật tư gốc thì thay đổi file gốc là các file khác updata theo, nhưng không ảnh hưởng đến liên kết nội bộ file.Ví dự như giá trị ô C1 sheet1 đang được lấy từ ô A1 sheet 3. Tại ô C1 sheet bấm Ctrl [ thì lập tức đến được ô A1 sheet3.
Thao tác này để kiểm tra các file excel quá tiện anh ạ.
https://www.fshare.vn/file/79G69GASSEAW Anh tải về file nén, giải nén, sau đó bấm mở file 2. Nha de xe, tại ô G8 sheet TH vat tu bấm Ctrl [ là hiểu ý đồ của em ngay anh ạ.
Việc biết lấy dữ liệu ở đâu đơn giản thôi mà bạn.Nếu làm như video thì không ổn lắm, file 0. Gia vat tu là 1 file em tổng hợp tất cả các vật tư sẽ dùng trên công trình, sau đó đi tìm giá nhập vào. Trong 1 công trình có khoảng 30 hạng mục như nhà để xe đó. Thủ công thì đứt điện ngay.
Nếu là chỉ để em làm ra giá trị thì không vấn đề, hàm Vlookup thì chỉ vài nốt nhạc là xong, nhưng quan trọng là giúp cho người kiểm tra dễ kiểm tra. Cách của anh Cá ngừ ở trên nhanh hơn hàm Vlookup rồi nhưng không biết lấy từ đâu thì chưa tròn bài.
Xin cảm ơn ACE đã quan tâm.
Thế nào là thủ công nhỉ?? File ví dụ của tôi có vài dòng thì tôi F2 Enter cho nó tiện. Chứ file có hàng nghìn dòng làm thế sao được. Dùng chức năng Find an Replace tùy chọn Formula, 1 nháy xong ngay.Nếu làm như video thì không ổn lắm, file 0. Gia vat tu là 1 file em tổng hợp tất cả các vật tư sẽ dùng trên công trình, sau đó đi tìm giá nhập vào. Trong 1 công trình có khoảng 30 hạng mục như nhà để xe đó. Thủ công thì đứt điện ngay.
Nếu là chỉ để em làm ra giá trị thì không vấn đề, hàm Vlookup thì chỉ vài nốt nhạc là xong, nhưng quan trọng là giúp cho người kiểm tra dễ kiểm tra. Cách của anh Cá ngừ ở trên nhanh hơn hàm Vlookup rồi nhưng không biết lấy từ đâu thì chưa tròn bài.
Xin cảm ơn ACE đã quan tâm.
Quả thật là tôi không hiểu thao tác Ctrl [ là làm j nữa, có bấm thử mà chả thấy nó có tác dụng jAnh Cá Ngừ mở thử file và dùng lệnh Ctrl [ chưa ạ? Ý nghĩa nó to lớn như vậy mà. Với lại code của anh đa đổ ra số chết, giờ ở file 0. Giá vật tư đó em thay đổi giá của 1 vật liệu nào đó thì lại phải dùng lại lệnh lần nữa rồi.
Anh Mạnh Linh, em biết thủ thuật đó, dùng để xử lý tình huống thì OK, nhưng đã code được như anh Cá Ngừ rồi thì thêm 1 xíu nữa là ổn, bấm nút là ăn tiền là tròn bài.
Trân trọng cảm ơn 2 Anh đã quan tâm và rất nhiệt tình.