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

Chia sẻ bởi:hands
★★★★★
Quảng cáo

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.

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.

www.giaiphapexcel.com/diendan/threads/nh%E1%BB%9D-anh-ch%E1%BB%8B-gi%C3%BAp-code-vba-t%C3%ACm-ki%E1%BA%BFm.161165/post-1076595

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 ạ

Thêm sheet Result2, chạy sub main

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

www.giaiphapexcel.com/diendan/threads/nh%E1%BB%9D-anh-ch%E1%BB%8B-gi%C3%BAp-code-vba-t%C3%ACm-ki%E1%BA%BFm.161165/post-1076776

Khóa học Power PI – Ứng dung trong Nhân sự
Khóa học SprinGO phù hợp

Khóa học Power PI – Ứng dung trong Nhân sự

TỔNG QUAN KHÓA HỌC: POWER BI CHO NGÀNH NHÂN SỰ Khóa học Power BI cho Nhân sự được thiết kế dành riêng cho các...

Xem khóa học
★★★★★ 5 ★ 1 👤 0 ▥ 0
Quảng cáo

Bạn nên đọc

Bình luận

Quảng cáo

Cũ vẫn chất

Xem thêm