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

Liên hệ QC

Hehe sau một hồi loay hoay OT làm theo gợi ý của anh Hai Lúa, dùng Recordset để lọc thì có thấy hơi khác một chút với Connection của bài Bạn @Hau151978 :

Recordset like sử dụng "*" còn Connection sử dụng "%"
Recordset không sử dụng where giống với Connection
Do đo OT cũng sửa lại chút hàm ConvertCriteria để tùy biến theo 2 phương pháp và kết hợp một thêm phần code của bác @HieuCD
OT cảm giác như dùng Recordset nhanh hơn Connection thì phải, toàn bộ code như sau , nhờ anh @Hai Lúa Miền Tây và mọi người góp ý ạ:
Mã:
Public Function ConvertCriteria(Field As String, Criteria As String, sLike As String) As String
    If Criteria = "*" Then
        ConvertCriteria = "TRUE"
    Else
        ConvertCriteria = "([" & Field & "] LIKE " & sLike & _
            Replace(Criteria, ";", sLike & " OR [" & Field & "] LIKE " & sLike) & sLike & ")"
    End If
End Function

Sub Filter_Rst()
    
    Dim Rst As New ADODB.Recordset, sCn As String, SrtSQL As String
    Dim wb As Workbook, shtFilter As Worksheet, sLike As String, Lr As Long
    Dim Customer As String, Product As String, Profit As String, fDate As Date, eDate As Date
    
    Const sDULIEU  As String = "Select * from [Orders$]"
    
    On Error GoTo ErrorProcess
    
    Set wb = ThisWorkbook
    Set shtFilter = wb.Worksheets("Filter")
    
    With shtFilter
        Lr = .Range("A" & Rows.Count).End(xlUp).Row
        If Lr > 3 Then .Range("A4:J" & Lr).ClearContents
        Customer = .Range("B1"):    Product = .Range("B2")
        fDate = .Range("D1"):       eDate = .Range("D2")
        Profit = .Range("E2")
    End With
    
    sLike = "*"
    SrtSQL = ConvertCriteria("Customer Name", Customer, sLike)
    SrtSQL = SrtSQL & " AND " & ConvertCriteria("Product category", Product, sLike)
    If Not (IsDate(fDate) And IsDate(eDate)) Or fDate > eDate Then
        MsgBox "Nhap lai dieu kien ngay thang", vbCritical, "Error"
        GoTo EndSub
    Else
        If SrtSQL <> Empty Then
            SrtSQL = SrtSQL & " AND ([Order date] >=#" & fDate & "#" & " AND [Order date] <=#" & eDate & "#)"
        Else
            SrtSQL = " ([Order date] >=#" & fDate & "#" & " And [Order date] <=#" & eDate & "#)"
        End If
    End If
    If Profit <> Empty Then
        If Profit = "=0" Then
            SrtSQL = SrtSQL & " AND (Profit=0)"
        Else
            SrtSQL = SrtSQL & " AND Profit" & Profit
        End If
    End If
    
    Debug.Print SrtSQL
    
    sCn = "Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties=Excel 12.0 Xml;Data Source=" & wb.FullName
    With Rst
        .Open sDULIEU, sCn, 1
        .Filter = SrtSQL
        shtFilter.Range("A4").CopyFromRecordset .DataSource
    End With
  
    GoTo EndSub
    
ErrorProcess:

    If Err <> 0 Then
        MsgBox Err.Number & "/" & Err.Source & "-->" & Err.Description, vbOKOnly + vbCritical, "Error"
    End If

EndSub:
    If Not Rst Is Nothing Then
        If Rst.State = adStateOpen Then Rst.Close
    End If
    Set Rst = Nothing
 
End Sub
 
Lão ấy không chiều chuộng, lão làm đơn giản vì lão biết là cổ thôi. :D
Biết là "cổ" mà vẫn không chiều, lại còn mắng là kiểu đặt điều kiện lọc kỳ cục. Còn làm là làm theo kiểu chuẩn không kỳ cục.
 
Biết là "cổ" mà vẫn không chiều, lại còn mắng là kiểu đặt điều kiện lọc kỳ cục. Còn làm là làm theo kiểu chuẩn không kỳ cục.
Không ổn rồi chú Mỹ xem giúp con câu lệnh bài #81 của con thế nào nếu B1 hoặc B2 có 1 điều kiện thì không sao còn từ 2 điều kiện trở lên là câu truy vấn bị lỗi. Hic -+*/
 
Không ổn rồi chú Mỹ xem giúp con câu lệnh bài #81 của con thế nào nếu B1 hoặc B2 có 1 điều kiện thì không sao còn từ 2 điều kiện trở lên là câu truy vấn bị lỗi. Hic -+*/
Hàm ConvertCriteria có split chuỗi ra đâu mà 2 với nhiều điều kiện
 
Hàm ConvertCriteria có split chuỗi ra đâu mà 2 với nhiều điều kiện
Ủa con vận dụng y chang bài 45 của bạn @Hau151978 mà Chú, con nghĩ là có thể là có thể do cú pháp áp dụng trong Recordset với nhiều điều kiện trong một trường mà con làm sang bị sai ở đâu đó ấy ạ. Hic con tưởng ngon ăn, giờ test thử mà thấy nhiều lỗi quá chú ạ, ví dụ lỗi nếu B1 không có gì mà B2 có cũng không được.. hic
 
Ủa con vận dụng y chang bài 45 của bạn @Hau151978 mà Chú, con nghĩ là có thể là có thể do cú pháp áp dụng trong Recordset với nhiều điều kiện trong một trường mà con làm sang bị sai ở đâu đó ấy ạ. Hic con tưởng ngon ăn, giờ test thử mà thấy nhiều lỗi quá chú ạ, ví dụ lỗi nếu B1 không có gì mà B2 có cũng không được.. hic
Cái sai chỉ nằm trong phạm vi cái hàm ConvertCriteria thôi.
- Trong đó có replace ";" nhưng không có tách chuỗi
- Trong đó chưa bắt chuỗi rỗng
 
@NHN_Phương bạn đặt breakpoint ở chỗ câu lệnh With srt, chạy code đến khi dừng để xem chuỗi strsql là gì đã.
Cảm ơn Bạn Hau151978 đã góp ý.
Mới đầu OT cũng đã kiểm tra câu lệnh truy vẫn nên trước with rst OT cũng đã đặt câu lệnh Debug.Print SrtSQL để xem nó là gì đó ạ.
Loay hoay mãi không được OT tắt máy rồi bạn ạ, hihi.
 
Tôi sai ở chỗ "chưa split chuỗi" và chưa biết nguyên nhân do máy chạy bị lỗi conflict gì đó.
Còn B1, B2 rỗng bị lỗi thì phải bắt trong hàm như tôi nói:
Mã:
    If Criteria = "*" Or Criteria = "" Then
        ConvertCriteria = "TRUE"
 
Tôi sai ở chỗ "chưa split chuỗi" và chưa biết nguyên nhân do máy chạy bị lỗi conflict gì đó.
Còn B1, B2 rỗng bị lỗi thì phải bắt trong hàm như tôi nói:
Mã:
    If Criteria = "*" Or Criteria = "" Then
        ConvertCriteria = "TRUE"

Bẫy lỗi trong hàm này có thể chưa ổn chú Mỹ ạ, vì ở câu lệnh:
SrtSQL = ConvertCriteria("Customer Name", Customer, sLike)
SrtSQL = SrtSQL & " AND " & ConvertCriteria("Product category", Product, sLike)
Nếu B1 rỗng thì B2 lỗi do câu lệnh dòng 2 có AND ở đầu ạ.
@NHN_Phương bạn đặt breakpoint ở chỗ câu lệnh With srt, chạy code đến khi dừng để xem chuỗi strsql là gì đã.

Xin anh @Hai Lúa Miền Tây và Bạn @Hau151978 cùng tất cả mọi người, OT thử gán SrtSQL cho câu lệnh sau thì không có lỗi:

SrtSQL = " ([Customer Name] LIKE *are* OR [Customer Name] LIKE *g*)" & _
" OR ([Product category] LIKE *O*)" & _
" OR ([Order date] >=#1/Jan/2011# And [Order date] <=#31/Dec/2011#)" & _
" OR Profit>0"

=> Nhưng kết quả sai.

Nhưng sau khi sửa lại gán SrtSQL cho câu lệnh sau :
SrtSQL = " ([Customer Name] LIKE *are* OR [Customer Name] LIKE *g*)" & _
" AND ([Product category] LIKE *O*)" & _
" AND ([Order date] >=#1/Jan/2011# And [Order date] <=#31/Dec/2011#)" & _
" AND Profit>0"

Thì code lỗi:
Err.Number: 3001
Err.Source: "ADODB.Recordset"
Err.Description: "Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another."

Như vậy là sao ạ,không sử dụng được AND ạ ? Hic
 
Bẫy lỗi trong hàm này có thể chưa ổn chú Mỹ ạ, vì ở câu lệnh:
SrtSQL = ConvertCriteria("Customer Name", Customer, sLike)
SrtSQL = SrtSQL & " AND " & ConvertCriteria("Product category", Product, sLike)
Nếu B1 rỗng thì B2 lỗi do câu lệnh dòng 2 có AND ở đầu ạ.
Mã:
SrtSQL = " ([Customer Name] LIKE *are* OR [Customer Name] LIKE *g*)" & _
" AND ([Product category] LIKE *O*)" & _
" AND ([Order date] >=#1/Jan/2011# And [Order date] <=#31/Dec/2011#)" & _
" AND Profit>0"
Nếu B1 và/ hoặc B2 rỗng thì làm sao lỗi được, câu điều kiện lọc SQL là
- B1 rỗng, B2 không rỗng:
SrtSQ = True AND ([Product category] LIKE *O*)" AND ...

- B1 không rỗng, B2 rỗng
SrtSQ = ([Customer Name] LIKE *are* OR [Customer Name] LIKE *g*) AND True AND ...

- Cả 2 đều rỗng
SrtSQ = True AND True AND ...

Ghi chú: phải test chứ đừng tưởng tượng. Nếu tưởng tượng thì phải tưởng tượng rằng B1 = "*" không lỗi thì B1="" cũng không lỗi do cùng gán True
Có gán null đâu mà dư And.
 
Nếu B1 và/ hoặc B2 rỗng thì làm sao lỗi được, câu điều kiện lọc SQL là
- B1 rỗng, B2 không rỗng:
SrtSQ = True AND ([Product category] LIKE *O*)" AND ...
- B1 không rỗng, B2 rỗng
SrtSQ = ([Customer Name] LIKE *are* OR [Customer Name] LIKE *g*) AND True AND ...
- Cả 2 đều rỗng
SrtSQ = True AND True AND ...

Ghi chú: phải test chứ đừng tưởng tượng
Vâng đúng là con chưa test thật nên mới nghĩ là có thể, nhưng đúng là kiểu bắt lỗi này như chú Mỹ giải thích con thấy đơn giản và hiệu quả thật thay vì phải sử dụng nhiểu hàm if, cảm ơn chú Mỹ.
 
OT thử gán SrtSQL cho câu lệnh sau thì không có lỗi:

=> Nhưng kết quả sai.

Nhưng sau khi sửa lại gán SrtSQL cho câu lệnh sau :

Thì code lỗi:
Err.Number: 3001
Err.Source: "ADODB.Recordset"
Err.Description: "Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another."
Theo mình đoán thì sau chuỗi sau LIKE phải để trong cặp dấu nháy, còn tại sao lệnh trên chạy được thì không rõ, chắc do may mắn, mình chỉ đoán thôi chứ toàn gán toàn bộ recordset xuống sheet, không làm kiểu này bao giờ.
 
Theo mình đoán thì sau chuỗi sau LIKE phải để trong cặp dấu nháy, còn tại sao lệnh trên chạy được thì không rõ, chắc do may mắn, mình chỉ đoán thôi chứ toàn gán toàn bộ recordset xuống sheet, không làm kiểu này bao giờ.
Xin chào bạn @Hau151978 ,
Vâng có thể là câu lệnh ban đầu chạy được do may mắn ạ, để cho chắc ăn
sau chuỗi sau LIKE phải để trong cặp dấu nháy
trong hàm ConvertCriteria OT cũng đã thay toàn bộ "%" thành "*" rồi:
Function ConvertCriteria(Field As String, Criteria As String) As String
If Criteria = "*" Then
ConvertCriteria = "TRUE"
Else
ConvertCriteria = "([" & Field & "] LIKE ""*" & Replace(Criteria, ";", "*"" OR [" & Field & "] LIKE ""*") & "*"")"
End If
End Function
nhưng vẫn không được ạ.

Ủa như vậy là làm như thế nào vậy Bạn, Bạn chỉ dẫn thêm với ạ. OT tham khảo và làm y chang kiểu trong bài viết này của anh @Hai Lúa Miền Tây mà:
 

File đính kèm

  • Orders-With Nulls.xlsm
    354.6 KB · Đọc: 11
Sao code của @Hau151978 chạy ra cả 2 dòng của năm 2012 nhỉ?

View attachment 252371
Em không biết, máy em chạy bình thường mà, chỉ có 4 dòng thôi. File bài 96.
@NHN_Phương lỗi này do MS quy định thế. Bạn đọc thêm https://docs.microsoft.com/en-us/of...esktop-database-reference/filter-property-ado, nếu có nhiều điều kiện lọc thì làm kiểu này rất dài. Còn sau LIKE ở đây nên dùng dấu nháy đơn.
 
Lần chỉnh sửa cuối:
Quay lại xài mảng, hoặc Power query cho chắc cú, với điều kiện lọc chuẩn. Chiều chuộng hoài cho mệt ;)
Nếu dùng ADO copy toàn bộ recordset thì câu lệnh SQL cũng đơn giản mà bác, em không hiểu sao máy bác lại ra vậy, chắc chạy nhiều bị loạn. Riêng Recordset.Filter mới có quy định chặt chẽ, không như mệnh đề WHERE.
 
Web KT
Back
Top Bottom