Lọc dữ liệu-chứa nhiều điều kiện lọc?

Liên hệ QC
Ùi, con chào Thầy ạ.
Con cảm ơn Thầy đã quan tâm đến vấn đề của con ạ.
Dạ điều kiện cột này có thể lựa chọn đầy đủ các điều kiện so sánh: (>=<) Thầy ạ.
Xử lý các điều kiện "<", "<=", "=", ">=", ">" không phải chuyện dễ.
Híc!
 
Xử lý các điều kiện "<", "<=", "=", ">=", ">" không phải chuyện dễ.
Híc!
Dạ vầng Thầy ạ, vậy có thể thiết kế thêm một ô nào nữa để lựa chọn các điều kiện "<", "<=", "=", ">=", ">" này được không ạ Thầy?
Ví dụ trong tập tin đính kèm con đã tách điều kiện trong ô E2 thành 2 ô E2 và F2 Thầy ạ.
 

File đính kèm

  • Orders-With Nulls v2(1).xlsx
    326.9 KB · Đọc: 13
Dạ vầng Thầy ạ, vậy có thể thiết kế thêm một ô nào nữa để lựa chọn các điều kiện "<", "<=", "=", ">=", ">" này được không ạ Thầy?
Ví dụ trong tập tin đính kèm con đã tách điều kiện trong ô E2 thành 2 ô E2 và F2 Thầy ạ.
Bạn thử code này xem đúng yêu cầu chưa:
Mã:
Option Explicit
Sub NTKTNN()
Dim sArr(), dArr(), CusName, ProCat, fDate As Long, tDate As Long, Profit As String, Bo As Boolean
Dim i As Long, J As Long, K As Long
Application.ScreenUpdating = False
With Sheets("Filter")
    CusName = Split(.Range("B1").Value, ";")
    ProCat = Split(.Range("B2").Value, ";")
    fDate = .Range("D1").Value
    tDate = .Range("D2").Value
    Profit = .Range("E2").Value
End With
With Sheets("Orders")
    sArr = .Range("A1:J" & .Cells(.Rows.Count, "A").End(xlUp).Rows).Value
    ReDim dArr(1 To UBound(sArr), 1 To UBound(sArr, 2))
    For i = 1 To UBound(sArr, 1)
        If UBound(CusName) >= 0 Then
            For J = 0 To UBound(CusName)
                If InStr(1, sArr(i, 8), CusName(J), 1) > 0 Then Bo = True: Exit For
            Next
            If Bo = False Then GoTo Next_I
            Bo = False
        End If
        If UBound(ProCat) >= 0 Then
            For J = 0 To UBound(ProCat)
                If InStr(1, sArr(i, 10), ProCat(J), 1) > 0 Then Bo = True: Exit For
            Next
            If Bo = False Then GoTo Next_I
            Bo = False
        End If
        If fDate > 0 And tDate > 0 Then
            If sArr(i, 2) >= fDate And sArr(i, 2) <= tDate Then Bo = True
            If Bo = False Then GoTo Next_I
            Bo = False
        End If
        If Profit <> "" Then
            If Evaluate(sArr(i, 6) & Profit) Then Bo = True
            If Bo = False Then GoTo Next_I
        End If
        K = K + 1
        For J = 1 To UBound(sArr, 2)
            dArr(K, J) = sArr(i, J)
        Next
Next_I:
    Next
End With
Sheets("Filter").Range("A4:J10000").ClearContents
Sheets("Filter").Range("A4").Resize(UBound(sArr), UBound(sArr, 2)) = dArr
Application.ScreenUpdating = True
End Sub
 

File đính kèm

  • Orders-With Nulls v2(1).xlsm
    337.2 KB · Đọc: 16
Lần chỉnh sửa cuối:
Mỗi vòng lặp lại phải tính lại UBound(CusName)

Dùng For each thì không cần kiểm tra Ubound.
Góp ý rất hay bác ạ, đúng là for each thì không cần phải kiểm tra ubound. Nhưng nếu không kiểm tra vậy thì một số trường hợp không có điều kiện (người để trống) code vẫn duyệt qua nó (em đang ví dụ với cusname), như vậy nó sẽ tính cái boolean là false và next sang i khác ạ
 
Góp ý rất hay bác ạ, đúng là for each thì không cần phải kiểm tra ubound. Nhưng nếu không kiểm tra vậy thì một số trường hợp không có điều kiện (người để trống) code vẫn duyệt qua nó (em đang ví dụ với cusname), như vậy nó sẽ tính cái boolean là false và next sang i khác ạ
Thì mình kiểm tra và oánh dấu ngay từ đầu ấy.

Dim flagCusName as boolean
If len(.Range("B1").Value) > 0 then
flagCusName = True
CusName = Split(.Range("B1").Value, ";")
Else
flagCusName = False
End if
'...
For i = 1 To UBound(sArr, 1)
If flagCusName = True then
For Each cuName in CusName
'...
Next
'...
Else
'...
End If
 
Thì mình kiểm tra và oánh dấu ngay từ đầu ấy.

Dim flagCusName as boolean
If len(.Range("B1").Value) > 0 then
flagCusName = True
CusName = Split(.Range("B1").Value, ";")
Else
flagCusName = False
End if
'...
For i = 1 To UBound(sArr, 1)
If flagCusName = True then
For Each cuName in CusName
'...
Next
'...
Else
'...
End If
Sao em thấy hình như bớt được khúc if nhưng phải tạo nhiều biến hơn phải không bác? :D
 
Ợ. Code xem ở giải thuật chứ đâu đi đếm biến với đếm dòng. @@
Thì em cũng biết code ai đâu đi đếm biến và dòng :D, nhưng em chỉ muốn biết theo cách đó có tối ưu hơn không, giả sử hai code tương đương nhau thì vẫn nên tiết kiệm biến và dòng cho dễ nhìn chứ ạ
 
Dạ vầng Thầy ạ, vậy có thể thiết kế thêm một ô nào nữa để lựa chọn các điều kiện "<", "<=", "=", ">=", ">" này được không ạ Thầy?
Ví dụ trong tập tin đính kèm con đã tách điều kiện trong ô E2 thành 2 ô E2 và F2 Thầy ạ.
Dùng ADO để Select bảng ban đầu. Với điều kiện ghép như [Customer name] dạng "a;b;c" ta dùng Replace và nối chuỗi để thay thế thành ([Customer name] like "%a%" OR [Customer name] like "%b%" OR [Customer name] like "%c%") rồi đưa vào điều kiện where thôi. Với điều kiện > hay >= dùng nối chuỗi bình thường.
 
Lần chỉnh sửa cuối:
Bạn thử code này xem đúng yêu cầu chưa:
Mã:
Option Explicit
Sub NTKTNN()
Dim sArr(), dArr(), CusName, ProCat, fDate As Long, tDate As Long, Profit As String, Bo As Boolean
Dim i As Long, J As Long, K As Long
Application.ScreenUpdating = False
With Sheets("Filter")
    CusName = Split(.Range("B1").Value, ";")
    ProCat = Split(.Range("B2").Value, ";")
    fDate = .Range("D1").Value
    tDate = .Range("D2").Value
    Profit = .Range("E2").Value
End With
With Sheets("Orders")
    sArr = .Range("A1:J" & .Cells(.Rows.Count, "A").End(xlUp).Rows).Value
    ReDim dArr(1 To UBound(sArr), 1 To UBound(sArr, 2))
    For i = 1 To UBound(sArr, 1)
        If UBound(CusName) >= 0 Then
            For J = 0 To UBound(CusName)
                If InStr(1, sArr(i, 8), CusName(J), 1) > 0 Then Bo = True: Exit For
            Next
            If Bo = False Then GoTo Next_I
            Bo = False
        End If
        If UBound(ProCat) >= 0 Then
            For J = 0 To UBound(ProCat)
                If InStr(1, sArr(i, 10), ProCat(J), 1) > 0 Then Bo = True: Exit For
            Next
            If Bo = False Then GoTo Next_I
            Bo = False
        End If
        If fDate > 0 And tDate > 0 Then
            If sArr(i, 2) >= fDate And sArr(i, 2) <= tDate Then Bo = True
            If Bo = False Then GoTo Next_I
            Bo = False
        End If
        If Profit <> "" Then
            If Evaluate(sArr(i, 6) & Profit) Then Bo = True
            If Bo = False Then GoTo Next_I
        End If
        K = K + 1
        For J = 1 To UBound(sArr, 2)
            dArr(K, J) = sArr(i, J)
        Next
Next_I:
    Next
End With
Sheets("Filter").Range("A4:J10000").ClearContents
Sheets("Filter").Range("A4").Resize(UBound(sArr), UBound(sArr, 2)) = dArr
Application.ScreenUpdating = True
End Sub
Mình thường viết kiểu nầy
Mã:
...
With Sheets("Filter")
    CusName = Split(";" & .Range("B1").Value, ";")
...
    For i = 1 To UBound(sArr, 1)      
            For J = 1 To UBound(CusName)
                If InStr(1, sArr(i, 8), CusName(J), 1) = 0 Then GoTo Next_I
            Next
...
 
For J = 1 To UBound(CusName) If InStr(1, sArr(i, 8), CusName(J), 1) = 0 Then GoTo Next_I
Ủa bác Hiếu, ubound của mảng split gốc 0 mà bác, với lại mảng cusname có nhiều phần tử, nếu duyệt phần tử đầu không có thì duyệt tiếp chứ theo em thấy code đó nếu gặp phần tử đầu tiên không có là next luôn rồi bác?
 
Ủa bác Hiếu, ubound của mảng split gốc 0 mà bác, với lại mảng cusname có nhiều phần tử, nếu duyệt phần tử đầu không có thì duyệt tiếp chứ theo em thấy code đó nếu gặp phần tử đầu tiên không có là next luôn rồi bác?
Mã:
CusName = Split(";" & .Range("B1").Value, ";")
Do thêm ";" & nên CusName (0) là giá trị trống bỏ qua. chỉ xét từ CusName (1)
Nhầm, chỉnh lại :)
Mã:
...
With Sheets("Filter")
    CusName = Split(";" & .Range("B1").Value, ";")
...
    For i = 1 To UBound(sArr, 1)     
            For J = 1 To UBound(CusName)
                If InStr(1, sArr(i, 8), CusName(J), 1) > 0 Then exit for
            Next
            If J = 1 + UBound(CusName) Then GoTo Next_I
...
 
Web KT
Back
Top Bottom