Nhờ anh/chị giúp code VBA tìm kiếm

Liên hệ QC

Erebus

Thành viên mới
Tham gia
30/10/16
Bài viết
41
Được thích
6
Em đang có 1 bài toán cần tìm kiếm nhiều giá trị và trả về theo điều kiện cụ thể như sau:
Có 2 trường hợp tìm kiếm
Trường hợp 1,
Tìm nhiều giá trị 1 lúc và có đủ 3 thông tin như 3 cột B,C,D
Kết quả trả về sheets Result (lấy thông tin từ cột Import) với yêu cầu như sau
- Trả về các dòng hàng tương ứng thỏa mãn điều kiện là cùng Item và số lượng lớn hơn vừa đủ
- Nếu 1 dòng không đủ số lượng thì trả về nhiều dòng để đủ tổng số lượng yêu cầu
- Nếu số lượng tồn không đủ số lượng xuất thì sẽ cảnh báo bằng màu sắc
Trường hợp 2.
Tìm kiếm nhiều giá trị 1 lúc và chỉ có thông tin cột B, C
Kết quả trả về tương tự, chỉ là ít hơn 1 điều kiện tìm kiếm

Chi tiết thông tin như tệp đính kèm, nhờ anh/chị giúp đỡ ạ

Em cảm ơn ạ
 

File đính kèm

  • Book1.xlsx
    19.2 KB · Đọc: 19
Em đang có 1 bài toán cần tìm kiếm nhiều giá trị và trả về theo điều kiện cụ thể như sau:
Có 2 trường hợp tìm kiếm
Trường hợp 1,
Tìm nhiều giá trị 1 lúc và có đủ 3 thông tin như 3 cột B,C,D
Kết quả trả về sheets Result (lấy thông tin từ cột Import) với yêu cầu như sau
- Trả về các dòng hàng tương ứng thỏa mãn điều kiện là cùng Item và số lượng lớn hơn vừa đủ
- Nếu 1 dòng không đủ số lượng thì trả về nhiều dòng để đủ tổng số lượng yêu cầu
- Nếu số lượng tồn không đủ số lượng xuất thì sẽ cảnh báo bằng màu sắc
Trường hợp 2.
Tìm kiếm nhiều giá trị 1 lúc và chỉ có thông tin cột B, C
Kết quả trả về tương tự, chỉ là ít hơn 1 điều kiện tìm kiếm

Chi tiết thông tin như tệp đính kèm, nhờ anh/chị giúp đỡ ạ

Em cảm ơn ạ
Yêu cầu Khó hiểu, nên nhập tay kết quả cho từng tình huống có thể xảy ra
 
Upvote 0
Em đang có 1 bài toán cần tìm kiếm nhiều giá trị và trả về theo điều kiện cụ thể như sau:
Có 2 trường hợp tìm kiếm
Trường hợp 1,
Tìm nhiều giá trị 1 lúc và có đủ 3 thông tin như 3 cột B,C,D
Kết quả trả về sheets Result (lấy thông tin từ cột Import) với yêu cầu như sau
- Trả về các dòng hàng tương ứng thỏa mãn điều kiện là cùng Item và số lượng lớn hơn vừa đủ
- Nếu 1 dòng không đủ số lượng thì trả về nhiều dòng để đủ tổng số lượng yêu cầu
- Nếu số lượng tồn không đủ số lượng xuất thì sẽ cảnh báo bằng màu sắc
Trường hợp 2.
Tìm kiếm nhiều giá trị 1 lúc và chỉ có thông tin cột B, C
Kết quả trả về tương tự, chỉ là ít hơn 1 điều kiện tìm kiếm

Chi tiết thông tin như tệp đính kèm, nhờ anh/chị giúp đỡ ạ

Em cảm ơn ạ
Làm theo ý hiểu.
Bạn thử code sau hãy nhấn vào mặt cười ở Sheet Result để xem và kiểm tra kết quả(chỉ cho trường hợp 1), trường hợp 2 và tô màu, kẻ khung định dạng bạn tự làm lấy.
 

File đính kèm

  • Book1 (Hoabk).xlsm
    29.8 KB · Đọc: 21
Upvote 0
Mình đã sửa lại file của bạn theo nhận định chủ quan của mình, bạn tham khảo
Lần sau nhớ tạo file giả (lập) chứ không cần file số liệu thực như của bạn đâu nha.
 

File đính kèm

  • FIND.rar
    28.1 KB · Đọc: 30
Upvote 0
Yêu cầu Khó hiểu, nên nhập tay kết quả cho từng tình huống có thể xảy ra
Vâng, em sửa lại thông tin, cập nhật thêm 3 trường hợp, a xem giúp em với ạ
Bài đã được tự động gộp:

Mình đã sửa lại file của bạn theo nhận định chủ quan của mình, bạn tham khảo
Lần sau nhớ tạo file giả (lập) chứ không cần file số liệu thực như của bạn đâu nha.
Cảm ơn bác rất nhiều ạ!, nhưng k hiểu sao em thay đổi dữ liệu và bấm run không chạy kết quả, em hơi gà mờ, bác hướng dẫn giúp em với nhé, em cập nhật lại 3 trường hợp cụ thể hơn như file đính kèm ạ
 

File đính kèm

  • Book1. rev1.xlsx
    21.7 KB · Đọc: 6
  • Book1. rev1.xlsx
    21.7 KB · Đọc: 2
Upvote 0
Theo mình hiểu thì bài này không đơn giản, như 2 bài giải phía trên đã làm.
Dạng như Solver, nếu mã ABC nào đó có 5 giá trị, phải tìm ra các trường hợp để tổng thỏa 2 điều kiện:
* Lớn hơn hoặc bằng giá trị cho trước
* Chênh lệch > giá trị cho trước là nhỏ nhất
Nếu chỉ có trường hợp tối đa 5 giá trị (như trong ví dụ), có thể dùng 5 cái for...next để giải quyết
Vấn đề là trong thực tế, mã ABC, hay XYZ nào đó có thể >5 giá trị, nên số lượng loop là không xác định được.
Có thể dùng VBA Solver, nhưng rất phức tạp, mình vẫn chưa nghĩ ra giải pháp nào khả thi
 
Upvote 0
Theo mình hiểu thì bài này không đơn giản, như 2 bài giải phía trên đã làm.
Dạng như Solver, nếu mã ABC nào đó có 5 giá trị, phải tìm ra các trường hợp để tổng thỏa 2 điều kiện:
* Lớn hơn hoặc bằng giá trị cho trước
* Chênh lệch > giá trị cho trước là nhỏ nhất
Nếu chỉ có trường hợp tối đa 5 giá trị (như trong ví dụ), có thể dùng 5 cái for...next để giải quyết
Vấn đề là trong thực tế, mã ABC, hay XYZ nào đó có thể >5 giá trị, nên số lượng loop là không xác định được.
Có thể dùng VBA Solver, nhưng rất phức tạp, mình vẫn chưa nghĩ ra giải pháp nào khả thi
Vâng, đúng như bác phân tích ạ, thực tế số lượng giá trị là không có giới hạn cụ thể nên bài toán này thật sự khó ạ
về phần chênh lệch > giá trị cho trước là nhỏ nhất cái này có thể bỏ bớt cũng được ạ, chỉ tổng các giá trị cần lớn hơn hoặc bằng giá trị cho trước, nếu không thì báo không còn đủ ạ
ngoài ra trường hợp tìm kiếm thứ 2 là bỏ qua thông tin "import CD" có thể tách thành 1 bảng kết quả khác với câu lệnh tìm kiếm khác cũng được , để giảm bớt phần nào những sự phức tạp ạ
 
Upvote 0
về phần chênh lệch > giá trị cho trước là nhỏ nhất cái này có thể bỏ bớt cũng được ạ, chỉ tổng các giá trị cần lớn hơn hoặc bằng giá trị cho trước, nếu không thì báo không còn đủ ạ
Giả sử:
Giá trị cần tìm: 100
Mã ABC có các giá trị:
1) 10
2) 89
3) 9
4) 2
5) 200

Các trường hợp tổng >=100
A) 1+2+3 = 108
B) 1+2+4 = 101
C) 1+2+5 = 299
v.v...

Bạn muốn chọn cái nào, A hay B hay C?
Tất nhiên không phải là C đúng không?
Nếu chọn bất kỳ thì dễ, còn chọn B mới là vấn đề khó.
 
Upvote 0
Giả sử:
Giá trị cần tìm: 100
Mã ABC có các giá trị:
1) 10
2) 89
3) 9
4) 2
5) 200

Các trường hợp tổng >=100
A) 1+2+3 = 108
B) 1+2+4 = 101
C) 1+2+5 = 299
v.v...

Bạn muốn chọn cái nào, A hay B hay C?
Tất nhiên không phải là C đúng không?
Nếu chọn bất kỳ thì dễ, còn chọn B mới là vấn đề khó.
Dúng là muốn chọn cái lớn hơn gần nhất anh ạ, tuy nhiên em hiểu được tính chất phức tạp của bài toán nên là em nghĩ bác giúp em cứ tổng lớn hơn hoặc bằng giá trị yêu cầu là được ạ.
 
Upvote 0
Vâng, em sửa lại thông tin, cập nhật thêm 3 trường hợp, a xem giúp em với ạ
Bài đã được tự động gộp:


Cảm ơn bác rất nhiều ạ!, nhưng k hiểu sao em thay đổi dữ liệu và bấm run không chạy kết quả, em hơi gà mờ, bác hướng dẫn giúp em với nhé, em cập nhật lại 3 trường hợp cụ thể hơn như file đính kèm ạ
Nếu có một Item có 3 thông số Item, Qty, Import CD và có thêm dòng thứ 2 chỉ có 2 thông số Item, Qty thì ưu tiên phân bổ cái nào trước ?
 
Upvote 0
Nếu có một Item có 3 thông số Item, Qty, Import CD và có thêm dòng thứ 2 chỉ có 2 thông số Item, Qty thì ưu tiên phân bổ cái nào trước ?
Em muốn ưu tiên cái có đủ cả 3 trước bác ạ, trường hợp nếu phức tạp quá thì bác tách giúp em thành 2 sheet, mỗi sheet check 1 kiểu cũng được ạ
 
Upvote 0
Giả sử:
Giá trị cần tìm: 100
Mã ABC có các giá trị:
1) 10
2) 89
3) 9
4) 2
5) 200

Các trường hợp tổng >=100
A) 1+2+3 = 108
B) 1+2+4 = 101
C) 1+2+5 = 299
v.v...

Bạn muốn chọn cái nào, A hay B hay C?
Tất nhiên không phải là C đúng không?
Nếu chọn bất kỳ thì dễ, còn chọn B mới là vấn đề khó.
Khó thì là khó, nhưng cũng làm được;
Nhưng tác giả bài đăng ngay chuyện giả lập dữ liệu cũng lom côm
Chỉ biết yêu cầu người khác cho mình kết qua như các trường hợp; nhưng với những dữ liệu của trang 'Import' thì không thể nào có kết quả như trang 'Diễn giải. . . ' (trong 2 file của #5)
Nếu chủ bài đăng muốn có kết quả như B thì nên giả lập lại file 1 lần nữa nghiêm túc hơn
 
Upvote 0
Khó thì là khó, nhưng cũng làm được;
Nhưng tác giả bài đăng ngay chuyện giả lập dữ liệu cũng lom côm
Chỉ biết yêu cầu người khác cho mình kết qua như các trường hợp; nhưng với những dữ liệu của trang 'Import' thì không thể nào có kết quả như trang 'Diễn giải. . . ' (trong 2 file của #5)
Nếu chủ bài đăng muốn có kết quả như B thì nên giả lập lại file 1 lần nữa nghiêm túc hơn
Vâng, cảm ơn bác đã giúp em nhận ra sự thiếu sót khi làm file giả lập, thiếu sót của em là đang để phần lớn các số import CD giống nhau.R
Rất xin lỗi các bác ạ.
Em gửi lại file cập nhật lại thông tin số import CD
Mong các bác giúp đỡ ạ
 

File đính kèm

  • Book1. rev2.xlsx
    21.9 KB · Đọc: 5
Upvote 0
Làm như vậy là cốt ý bạn luyện kỹ năng đoán câu hỏi của người ta, hay bạn rảnh quá làm chơi?
Trên 68% (1 độ lệch chuẩn) là phải viết lại rồi.

...
Chỉ biết yêu cầu người khác cho mình kết qua như các trường hợp; nhưng với những dữ liệu của trang 'Import' thì không thể nào có kết quả như trang 'Diễn giải. . . ' (trong 2 file của #5)
...
Nhưng em chỉ cần xin code. Kiểm soát lô gic là chuyện của mấy anh chị mờ.
 
Upvote 0
. . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . .
 

File đính kèm

  • DownLoads.rar
    31.3 KB · Đọc: 14
Upvote 0
. . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . .
Em cảm ơn bác rất nhiều ạ,
Vì kiến thức về mảng này của em còn rất non kém nên tạm thời em thử thì hiểu như sau:
1, Trường hợp 1, tìm kiếm giá trị ở vùng [J4:L6], nếu không có giá trị tương ứng thì giá trị tìm kiếm chuyển thành màu hồng, nếu không đủ số lượng thì màu tím.
2, Trường hợp 2, tìm kiếm giá trị ở vùng [J15:L18], kết quả cũng trả về tương tự
3, Trường hợp 3 thì bác tạm chưa viết

về phần kết quả hiển thị, là các kết quả ngẫu nhiên đáp ứng điều kiện Item và import tương ứng lớn và tổng số lượng hơn hoặc bằng số lượng tìm kiếm.

Em muốn nhờ bác điều chỉnh thêm giúp em một chút là vì trên thực tế 2 trường hợp này thực tế là 1 ạ, tức là em sẽ không biết số lượng tìm kiếm sẽ lớn hơn hoặc nhỏ hơn, nên phải tìm kiếm trả về kết quả mới biết được ạ
và bác giúp em viết thêm trường hợp còn lại là giá trị "Import CD" bỏ trống với nhé
Em cảm ơn bác nhiều ạ
 
Upvote 0
. . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . .
Em xin phép bổ sung thêm 1 số chi tiết ở phần hiển thị kết quả ạ,
bác giúp em cho hiển thị cả các cột Origin, Exported qty và Remaining Qty ạ,
ngoài ra khi so sánh số lượng thì sẽ dùng tổng số lượng còn lại "Remaining qty" để so sánh với số lượng cần kiểm tra chứ không phải là cột "Qty" ạ
Bác chỉnh giúp em một chút với ạ
 
Upvote 0
Em muốn ưu tiên cái có đủ cả 3 trước bác ạ, trường hợp nếu phức tạp quá thì bác tách giúp em thành 2 sheet, mỗi sheet check 1 kiểu cũng được ạ
Thêm sheet Result2, chạy sub main
Mã:
Option Explicit

Sub Main()
  Dim arr(), aDL(), S, res(), res2()
  Dim sRow&, k&, i&, j&, iTem$, QTy#, iCD$

For i = 5 To 7
Range("J" & i).Font.Color = -16776961
Next i
  With Sheets("Import")
    aDL = .Range("A3:I" & .Range("A1048000").End(xlUp).Row).Value
  End With
  sRow = UBound(aDL)
  ReDim res(1 To sRow, 1 To 8)
  ReDim res2(1 To sRow, 1 To 8)
  With Sheets("Check")
    arr = .Range("B2:D" & .Range("B1048000").End(xlUp).Row).Value
  End With
  For i = 1 To UBound(arr)
    iTem = arr(i, 1): QTy = arr(i, 2): iCD = CStr(arr(i, 3))
    If iTem <> Empty And QTy > 0 Then
      If iCD <> Empty Then
        Call SumFind(aDL, res, k, sRow, iTem, QTy, iCD)
      End If
    End If
  Next i
  With Sheets("Result")
    i = .Range("A1048000").End(xlUp).Row
    If i > 2 Then .Range("A3:H" & i).Clear
    If k Then
      .Range("A3").Resize(k, 8) = res
      .Range("A3").Resize(k, 8).Borders.LineStyle = 1
      For i = 3 To k + 2
        If .Range("B" & i).Value = Empty Then .Range("A" & i).Font.Color = -16776961
      Next i
    End If
  End With
  k = 0
  ReDim res(1 To sRow, 1 To 8)
  For i = 1 To UBound(arr)
    iTem = arr(i, 1): QTy = arr(i, 2): iCD = CStr(arr(i, 3))
    If iCD = Empty Then
      If iTem <> Empty And QTy > 0 Then
        Call SumFind(aDL, res, k, sRow, iTem, QTy, iCD)
      End If
    End If
  Next i
  With Sheets("Result2")
    i = .Range("A1048000").End(xlUp).Row
    If i > 2 Then .Range("A3:H" & i).Clear
    If k Then
      .Range("A3").Resize(k, 8) = res
      .Range("A3").Resize(k, 8).Borders.LineStyle = 1
      For i = 3 To k + 2
        If .Range("B" & i).Value = Empty Then .Range("A" & i).Font.Color = -16776961
      Next i
    End If
  End With
End Sub

Private Sub SumFind(aDL, aRes, k, sRow, iTem, QTy, iCD)
  Dim Data(), arr(), S, tmp#, tSum#, dMin#, i&, N&, q&, j&, r&, t$

  dMin = 1000000000
  For i = 1 To sRow
    tmp = aDL(i, 9)
    If aDL(i, 1) = iTem And tmp > 0 Then
      If CStr(aDL(i, 2)) = iCD Or iCD = Empty Then
        If tmp = QTy Then
          k = k + 1
          For j = 1 To 6
            aRes(k, j) = aDL(i, j)
          Next j
          aRes(k, 7) = aDL(i, 8): aRes(k, 8) = aDL(i, 9)
          aDL(i, 1) = Empty
          Exit Sub
        ElseIf tmp > QTy Then
          If dMin > tmp Then dMin = tmp: t = "," & i
        ElseIf tmp > 0 Then
          N = N + 1
          ReDim Preserve Data(1 To 2, 1 To N)
          Data(1, N) = tmp: Data(2, N) = i
        End If
      End If
    End If
  Next i
 
If N > 0 Then
  Call QuickSort(Data)
  ReDim arr(1 To N)
  arr(1) = 1:     tSum = Data(1, 1)
  N = 1:          q = 1
  Do While QTy <> -1 'tSum
    If arr(1) = UBound(Data, 2) Then Exit Do
    If tSum > QTy Then
      If dMin > tSum Then
        dMin = tSum
        t = Empty
        For i = 1 To N
          t = t & "," & Data(2, arr(i))
        Next i
      End If
      q = arr(N - 1) + 1
      tSum = tSum - Data(1, arr(N)) - Data(1, arr(N - 1)) + Data(1, q)
      N = N - 1
      arr(N) = q
    Else
      If q = UBound(Data, 2) Then
        q = arr(N - 1) + 1
        tSum = tSum - Data(1, arr(N)) - Data(1, arr(N - 1)) + Data(1, q)
        N = N - 1
        arr(N) = q
      Else
        q = q + 1
        tSum = tSum + Data(1, q)
        N = N + 1
        arr(N) = q
      End If
    End If
    If QTy = tSum Then
      t = Empty
      For i = 1 To N
        t = t & "," & Data(2, arr(i))
      Next i
      Exit Do
    End If
  Loop
End If

  If t <> Empty Then
    S = Split(t, ",")
    For i = 1 To UBound(S)
      r = CLng(S(i))
      k = k + 1
      For j = 1 To 6
        aRes(k, j) = aDL(r, j)
      Next j
      aRes(k, 7) = aDL(r, 8): aRes(k, 8) = aDL(r, 9)
      aDL(r, 1) = Empty
    Next i
  Else
    k = k + 1
    aRes(k, 1) = iTem
  End If
End Sub

Private Sub QuickSort(Data)
  Dim oSList As Object, sArr, S, j&, k&, jk&, m&

  Set oSList = CreateObject("System.Collections.SortedList")
  For j = LBound(Data, 2) To UBound(Data, 2)
    oSList.iTem(Data(1, j)) = oSList.iTem(Data(1, j)) & "," & j
  Next j
  sArr = Data
  For j = 0 To oSList.Count - 1
    S = Split(oSList.GetByIndex(j), ",")
    For m = 1 To UBound(S)
      jk = CLng(S(m))
        k = k + 1
        Data(1, k) = sArr(1, jk): Data(2, k) = sArr(2, jk)
    Next m
  Next j
  Set oSList = Nothing
End Sub
 

File đính kèm

  • Book1. rev2.xlsm
    48.8 KB · Đọc: 33
Upvote 0
Thêm sheet Result2, chạy sub main
Mã:
Option Explicit

Sub Main()
  Dim arr(), aDL(), S, res(), res2()
  Dim sRow&, k&, i&, j&, iTem$, QTy#, iCD$

For i = 5 To 7
Range("J" & i).Font.Color = -16776961
Next i
  With Sheets("Import")
    aDL = .Range("A3:I" & .Range("A1048000").End(xlUp).Row).Value
  End With
  sRow = UBound(aDL)
  ReDim res(1 To sRow, 1 To 8)
  ReDim res2(1 To sRow, 1 To 8)
  With Sheets("Check")
    arr = .Range("B2:D" & .Range("B1048000").End(xlUp).Row).Value
  End With
  For i = 1 To UBound(arr)
    iTem = arr(i, 1): QTy = arr(i, 2): iCD = CStr(arr(i, 3))
    If iTem <> Empty And QTy > 0 Then
      If iCD <> Empty Then
        Call SumFind(aDL, res, k, sRow, iTem, QTy, iCD)
      End If
    End If
  Next i
  With Sheets("Result")
    i = .Range("A1048000").End(xlUp).Row
    If i > 2 Then .Range("A3:H" & i).Clear
    If k Then
      .Range("A3").Resize(k, 8) = res
      .Range("A3").Resize(k, 8).Borders.LineStyle = 1
      For i = 3 To k + 2
        If .Range("B" & i).Value = Empty Then .Range("A" & i).Font.Color = -16776961
      Next i
    End If
  End With
  k = 0
  ReDim res(1 To sRow, 1 To 8)
  For i = 1 To UBound(arr)
    iTem = arr(i, 1): QTy = arr(i, 2): iCD = CStr(arr(i, 3))
    If iCD = Empty Then
      If iTem <> Empty And QTy > 0 Then
        Call SumFind(aDL, res, k, sRow, iTem, QTy, iCD)
      End If
    End If
  Next i
  With Sheets("Result2")
    i = .Range("A1048000").End(xlUp).Row
    If i > 2 Then .Range("A3:H" & i).Clear
    If k Then
      .Range("A3").Resize(k, 8) = res
      .Range("A3").Resize(k, 8).Borders.LineStyle = 1
      For i = 3 To k + 2
        If .Range("B" & i).Value = Empty Then .Range("A" & i).Font.Color = -16776961
      Next i
    End If
  End With
End Sub

Private Sub SumFind(aDL, aRes, k, sRow, iTem, QTy, iCD)
  Dim Data(), arr(), S, tmp#, tSum#, dMin#, i&, N&, q&, j&, r&, t$

  dMin = 1000000000
  For i = 1 To sRow
    tmp = aDL(i, 9)
    If aDL(i, 1) = iTem And tmp > 0 Then
      If CStr(aDL(i, 2)) = iCD Or iCD = Empty Then
        If tmp = QTy Then
          k = k + 1
          For j = 1 To 6
            aRes(k, j) = aDL(i, j)
          Next j
          aRes(k, 7) = aDL(i, 8): aRes(k, 8) = aDL(i, 9)
          aDL(i, 1) = Empty
          Exit Sub
        ElseIf tmp > QTy Then
          If dMin > tmp Then dMin = tmp: t = "," & i
        ElseIf tmp > 0 Then
          N = N + 1
          ReDim Preserve Data(1 To 2, 1 To N)
          Data(1, N) = tmp: Data(2, N) = i
        End If
      End If
    End If
  Next i
 
If N > 0 Then
  Call QuickSort(Data)
  ReDim arr(1 To N)
  arr(1) = 1:     tSum = Data(1, 1)
  N = 1:          q = 1
  Do While QTy <> -1 'tSum
    If arr(1) = UBound(Data, 2) Then Exit Do
    If tSum > QTy Then
      If dMin > tSum Then
        dMin = tSum
        t = Empty
        For i = 1 To N
          t = t & "," & Data(2, arr(i))
        Next i
      End If
      q = arr(N - 1) + 1
      tSum = tSum - Data(1, arr(N)) - Data(1, arr(N - 1)) + Data(1, q)
      N = N - 1
      arr(N) = q
    Else
      If q = UBound(Data, 2) Then
        q = arr(N - 1) + 1
        tSum = tSum - Data(1, arr(N)) - Data(1, arr(N - 1)) + Data(1, q)
        N = N - 1
        arr(N) = q
      Else
        q = q + 1
        tSum = tSum + Data(1, q)
        N = N + 1
        arr(N) = q
      End If
    End If
    If QTy = tSum Then
      t = Empty
      For i = 1 To N
        t = t & "," & Data(2, arr(i))
      Next i
      Exit Do
    End If
  Loop
End If

  If t <> Empty Then
    S = Split(t, ",")
    For i = 1 To UBound(S)
      r = CLng(S(i))
      k = k + 1
      For j = 1 To 6
        aRes(k, j) = aDL(r, j)
      Next j
      aRes(k, 7) = aDL(r, 8): aRes(k, 8) = aDL(r, 9)
      aDL(r, 1) = Empty
    Next i
  Else
    k = k + 1
    aRes(k, 1) = iTem
  End If
End Sub

Private Sub QuickSort(Data)
  Dim oSList As Object, sArr, S, j&, k&, jk&, m&

  Set oSList = CreateObject("System.Collections.SortedList")
  For j = LBound(Data, 2) To UBound(Data, 2)
    oSList.iTem(Data(1, j)) = oSList.iTem(Data(1, j)) & "," & j
  Next j
  sArr = Data
  For j = 0 To oSList.Count - 1
    S = Split(oSList.GetByIndex(j), ",")
    For m = 1 To UBound(S)
      jk = CLng(S(m))
        k = k + 1
        Data(1, k) = sArr(1, jk): Data(2, k) = sArr(2, jk)
    Next m
  Next j
  Set oSList = Nothing
End Sub
Đỉnh cao!
Em cảm ơn bác rất nhiều ạ.
Kết quả còn trả về giá trị lớn hơn gần nhất với lượng cần tìm nữa
Với kiến thức quá ít của em thì nhìn vào code chưa hiểu gì cả :)
Em cảm ơn rất nhiều ạ
 
Upvote 0
Thêm sheet Result2, chạy sub main
Mã:
Option Explicit

Sub Main()
  Dim arr(), aDL(), S, res(), res2()
  Dim sRow&, k&, i&, j&, iTem$, QTy#, iCD$

For i = 5 To 7
Range("J" & i).Font.Color = -16776961
Next i
  With Sheets("Import")
    aDL = .Range("A3:I" & .Range("A1048000").End(xlUp).Row).Value
  End With
  sRow = UBound(aDL)
  ReDim res(1 To sRow, 1 To 8)
  ReDim res2(1 To sRow, 1 To 8)
  With Sheets("Check")
    arr = .Range("B2:D" & .Range("B1048000").End(xlUp).Row).Value
  End With
  For i = 1 To UBound(arr)
    iTem = arr(i, 1): QTy = arr(i, 2): iCD = CStr(arr(i, 3))
    If iTem <> Empty And QTy > 0 Then
      If iCD <> Empty Then
        Call SumFind(aDL, res, k, sRow, iTem, QTy, iCD)
      End If
    End If
  Next i
  With Sheets("Result")
    i = .Range("A1048000").End(xlUp).Row
    If i > 2 Then .Range("A3:H" & i).Clear
    If k Then
      .Range("A3").Resize(k, 8) = res
      .Range("A3").Resize(k, 8).Borders.LineStyle = 1
      For i = 3 To k + 2
        If .Range("B" & i).Value = Empty Then .Range("A" & i).Font.Color = -16776961
      Next i
    End If
  End With
  k = 0
  ReDim res(1 To sRow, 1 To 8)
  For i = 1 To UBound(arr)
    iTem = arr(i, 1): QTy = arr(i, 2): iCD = CStr(arr(i, 3))
    If iCD = Empty Then
      If iTem <> Empty And QTy > 0 Then
        Call SumFind(aDL, res, k, sRow, iTem, QTy, iCD)
      End If
    End If
  Next i
  With Sheets("Result2")
    i = .Range("A1048000").End(xlUp).Row
    If i > 2 Then .Range("A3:H" & i).Clear
    If k Then
      .Range("A3").Resize(k, 8) = res
      .Range("A3").Resize(k, 8).Borders.LineStyle = 1
      For i = 3 To k + 2
        If .Range("B" & i).Value = Empty Then .Range("A" & i).Font.Color = -16776961
      Next i
    End If
  End With
End Sub

Private Sub SumFind(aDL, aRes, k, sRow, iTem, QTy, iCD)
  Dim Data(), arr(), S, tmp#, tSum#, dMin#, i&, N&, q&, j&, r&, t$

  dMin = 1000000000
  For i = 1 To sRow
    tmp = aDL(i, 9)
    If aDL(i, 1) = iTem And tmp > 0 Then
      If CStr(aDL(i, 2)) = iCD Or iCD = Empty Then
        If tmp = QTy Then
          k = k + 1
          For j = 1 To 6
            aRes(k, j) = aDL(i, j)
          Next j
          aRes(k, 7) = aDL(i, 8): aRes(k, 8) = aDL(i, 9)
          aDL(i, 1) = Empty
          Exit Sub
        ElseIf tmp > QTy Then
          If dMin > tmp Then dMin = tmp: t = "," & i
        ElseIf tmp > 0 Then
          N = N + 1
          ReDim Preserve Data(1 To 2, 1 To N)
          Data(1, N) = tmp: Data(2, N) = i
        End If
      End If
    End If
  Next i
 
If N > 0 Then
  Call QuickSort(Data)
  ReDim arr(1 To N)
  arr(1) = 1:     tSum = Data(1, 1)
  N = 1:          q = 1
  Do While QTy <> -1 'tSum
    If arr(1) = UBound(Data, 2) Then Exit Do
    If tSum > QTy Then
      If dMin > tSum Then
        dMin = tSum
        t = Empty
        For i = 1 To N
          t = t & "," & Data(2, arr(i))
        Next i
      End If
      q = arr(N - 1) + 1
      tSum = tSum - Data(1, arr(N)) - Data(1, arr(N - 1)) + Data(1, q)
      N = N - 1
      arr(N) = q
    Else
      If q = UBound(Data, 2) Then
        q = arr(N - 1) + 1
        tSum = tSum - Data(1, arr(N)) - Data(1, arr(N - 1)) + Data(1, q)
        N = N - 1
        arr(N) = q
      Else
        q = q + 1
        tSum = tSum + Data(1, q)
        N = N + 1
        arr(N) = q
      End If
    End If
    If QTy = tSum Then
      t = Empty
      For i = 1 To N
        t = t & "," & Data(2, arr(i))
      Next i
      Exit Do
    End If
  Loop
End If

  If t <> Empty Then
    S = Split(t, ",")
    For i = 1 To UBound(S)
      r = CLng(S(i))
      k = k + 1
      For j = 1 To 6
        aRes(k, j) = aDL(r, j)
      Next j
      aRes(k, 7) = aDL(r, 8): aRes(k, 8) = aDL(r, 9)
      aDL(r, 1) = Empty
    Next i
  Else
    k = k + 1
    aRes(k, 1) = iTem
  End If
End Sub

Private Sub QuickSort(Data)
  Dim oSList As Object, sArr, S, j&, k&, jk&, m&

  Set oSList = CreateObject("System.Collections.SortedList")
  For j = LBound(Data, 2) To UBound(Data, 2)
    oSList.iTem(Data(1, j)) = oSList.iTem(Data(1, j)) & "," & j
  Next j
  sArr = Data
  For j = 0 To oSList.Count - 1
    S = Split(oSList.GetByIndex(j), ",")
    For m = 1 To UBound(S)
      jk = CLng(S(m))
        k = k + 1
        Data(1, k) = sArr(1, jk): Data(2, k) = sArr(2, jk)
    Next m
  Next j
  Set oSList = Nothing
End Sub
Bác cho em hỏi thêm chút ạ,
trường hợp em muốn ưu tiên lấy các điều kiện đó theo origin là "VIETNAM" trước, nếu không còn đủ mới lấy các loại khác (các loại khác không phân biệt) và sau cùng là trả về kết quả trống như trước thì có được không ạ?
 
Upvote 0
Web KT

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

Back
Top Bottom