My Assistant
![]() ![]() |
|
|
Mar 29 2010, 04:28 PM
Post
#1
|
|
|
UtterAccess Enthusiast Posts: 56 |
Hello All:
I'm stumped and looking for a solution or alternative. I have a form with a subform that is in datasheet view. I would like for the users to filter the subform and then click on a "select all" button in the parent form that would then check off a checkbox for the current filter. This would be done through and update query written in dynamic SQL. Seems simple enough. Something like this... "UPDATE tblData " & _ "SET ysnSelect = 1 WHERE " & _ strWhere The problem, so far, is that when I use sbfData.filter... the filter is qualified by the subform name. (i.e. ([sbfData].[state] = "MT"). So, obviously, when I try to run the query it throws an error that the identifier could not be bound. Therefore the query won't run and the suform is not updated. Any insight or suggestions for alternative methods is greatly appreciated. Please let me know if you need further explanation. Thanks |
|
|
|
Apr 9 2010, 06:00 AM
Post
#2
|
|
|
New Member Posts: 5 |
Hi,
the problem with filters in Access is that unfortunately the Access programmers didn't think about the filter syntax. The filter syntax is the same like before, like used in ACCDB/MDB in the Jet style and so it doesn't work as WHERE clause. I had the same problem before. Access handles it internally to convert the filters into SQL syntax but there is no way to get this converted filter. I can only recommend to use filters carefully in Access ADP, they often causes crashes, especially in continous forms with a lot records (>10000). I use the following functions of my ADO library to solve this problem. The first one converts the most common filters of Access into the SQL Server style (fnErr is a function to display an error message). The more complicated filters like "first quarter of year" of a date field are not supported with this: CODE ' Converts a form filter created in Acces into a format which is usable as WHERE clause ' for SQL Server ' Filters with other functions like "DatePart", "Year" and so on are not supported by ADO ' For more infos look here: http://msdn.microsoft.com/en-us/library/ms676691%28VS.85%29.aspx Public Function fnSQLConvertFilter(frm As Form) As String Dim strFilter As Variant Dim strField As String Dim strValue1 As String Dim strValue2 As String Dim lngPos As Long Dim lngPos2 As Long strADOErr = "OK" On Error GoTo fnSQLConvertFilter_Error strFilter = frm.Filter If Nz(strFilter) = "" Then fnSQLConvertFilter = "" Exit Function End If strFilter = Replace(strFilter, "[" & frm.Name & "].", "") strFilter = Replace(strFilter, """", "'") strFilter = Replace(strFilter, "#", "'") strFilter = Replace(strFilter, "Date()", "GetDate()") strFilter = Replace(strFilter, "Now()", "GetDate()") strFilter = Replace(strFilter, "True", "1") strFilter = Replace(strFilter, "False", "0") strFilter = Replace(strFilter, "*", "%") strFilter = Replace(strFilter, "SELECT % ", "SELECT * ") strFilter = Replace(strFilter, " Alike ", " LIKE ") ' -------- ' Replace a "BETWEEN"-Filter with ">=" and "<=" lngPos = InStr(strFilter, "BETWEEN") If lngPos > 0 Then strField = Trim(Mid(strFilter, InStrRev(strFilter, "[", lngPos), InStrRev(strFilter, "]", lngPos) - InStrRev(strFilter, "[", lngPos) + 1)) strFilter = Left(strFilter, lngPos - 1) & Replace(strFilter, "BETWEEN", " >= ", lngPos, 1) strFilter = Left(strFilter, lngPos - 1) & Replace(strFilter, " AND ", " AND " & strField & " <= ", lngPos, 1) End If strFilter = Replace(strFilter, "%53", "") ' -------- ' ADO recordsets sends an error if "LIKE '%xxx'" is used. ' This exchanges the "LIKE '%xxx'" to "LIKE '%xxx%'" (second "%" at the end) ' to avoid the error. lngPos = 1 Do lngPos = InStr(lngPos, strFilter, "LIKE '%") If lngPos > 0 Then lngPos2 = InStr(lngPos + 6, strFilter, "'") If Mid(strFilter, lngPos2 - 1, 1) <> "%" Then strFilter = Left(strFilter, lngPos2 - 1) & "%" & Right(strFilter, Len(strFilter) - lngPos2 + 1) End If lngPos = lngPos2 End If Loop Until lngPos = 0 fnSQLConvertFilter = strFilter fnSQLConvertFilter_Exit: Exit Function fnSQLConvertFilter_Error: strADOErr = "ERROR" Select Case Err Case Else fnErr "modODBC->fnSQLConvertFilter", True Resume fnSQLConvertFilter_Exit End Select End Function The next function uses the above one to get back a recordset containing the filtered records or a SQL string containing the needed command to get these records: CODE ' fnADOSelectFilteredForm ' Date: 28.08.2009 ' ' Returns the same records which are displayed in a form in an Access ADP ' filtered by any sort of user defined filter ' ' The RecordSource of the form should have the following structure: ' "SELECT Whatever FROM MyTable WHERE FormCondition ORDER BY FormOrder" ' ' GROUP and HAVING clauses are not supported. ' Public Function fnADOSelectFilteredForm(frm As Form, Optional strAddWhere As String = "", _ Optional intLockType As ADODB.LockTypeEnum = adLockReadOnly, _ Optional intOpenMode As ADODB.CursorTypeEnum = adOpenStatic, _ Optional intReturnAs As enmADOReturnAs = enmADOReturnAsRecordset) As ADODB.Recordset Dim rsADO As ADODB.Recordset Dim strSQL As String Dim strOrderBy As String Dim strWhere As String Dim strFilter As String Dim strServerFilter As String Dim strWhereWord As String Dim strSchema As String Dim strIDs As String On Error GoTo fnADOSelectFilteredForm_Error Set rsADO = frm.Recordset.Clone strSQL = rsADO.Source ' stored procedure was used, no SQL string possible If Left(UCase(strSQL), 4) = "EXEC" Then ' get the user defined filter of the form and convert it to SQL server syntax strFilter = fnSQLConvertFilter(frm) If strAddWhere <> "" Then strFilter = strFilter & " AND (" & strAddWhere & ") " If frm.ServerFilter <> "" Then strFilter = strFilter & " AND (" & frm.ServerFilter & ") " ' set the same filter as used in the form to the copy of the recordset rsADO.Filter = strFilter Set fnADOSelectFilteredForm = rsADO GoTo fnADOSelectFilteredForm_Exit ' ------------> End If ' Neither SELECT nor EXE then a direct table was entered as RecordSource of the form If Left(UCase(strSQL), 6) <> "SELECT" And Left(UCase(strSQL), 4) <> "EXEC" Then If frm.RecordSourceQualifier = Left(strSQL, Len(frm.RecordSourceQualifier)) Then strSchema = "[" & frm.RecordSourceQualifier & "]." strSQL = Right(strSQL, Len(strSQL) - Len(frm.RecordSourceQualifier) - 1) End If strSQL = "SELECT * FROM " & strSchema & strSQL If frm.OrderByOnLoad = True And Nz(frm.OrderBy) <> "" Then strSQL = strSQL & " ORDER BY " & frm.OrderBy End If End If If InStrRev(UCase(strSQL), "ORDER BY") > 0 Then strOrderBy = Trim(Right(strSQL, Len(strSQL) - InStrRev(UCase(strSQL), "ORDER BY") + 1)) strSQL = Trim(Left(strSQL, Len(strSQL) - Len(strOrderBy))) Else strOrderBy = "" End If If InStrRev(UCase(strSQL), "WHERE") > 0 Then strWhere = Trim(Right(strSQL, Len(strSQL) - InStrRev(UCase(strSQL), "WHERE") + 1)) strSQL = Trim(Left(strSQL, Len(strSQL) - Len(strWhere))) strWhere = " (" & Trim(Right(strWhere, Len(strWhere) - 5)) & ") " Else strWhere = "" End If If frm.ServerFilter <> "" Then strServerFilter = " (" & frm.ServerFilter & ") " End If strFilter = fnSQLConvertFilter(frm) If strFilter <> "" Then If frm.FilterOn = True Then strFilter = " (" & strFilter & ") " Else strFilter = "" End If End If If strWhere <> "" Or strAddWhere <> "" Or strServerFilter <> "" Or strFilter <> "" Then strWhereWord = " WHERE " Else strWhereWord = " " End If If strAddWhere <> "" Then strAddWhere = " (" & strAddWhere & ") " strWhere = IIf(strWhere <> "", strWhere, "") & _ IIf(strFilter <> "", " AND " & strFilter, "") & _ IIf(strServerFilter <> "", " AND " & strServerFilter, "") & _ IIf(strAddWhere <> "", " AND " & strAddWhere, "") If Left(strWhere, 5) = " AND " Then strWhere = Right(strWhere, Len(strWhere) - 5) strSQL = strSQL & strWhereWord & " " & strWhere & " " & IIf(strOrderBy <> "", strOrderBy, "") Select Case intReturnAs Case enmADOReturnAsRecordset Set fnADOSelectFilteredForm = fnADOSelectCommon(strSQL, intLockType, intOpenMode) Case enmADOReturnAsSQLString Set fnADOSelectFilteredForm = Nothing End Select strADOSQLString = strSQL fnADOSelectFilteredForm_Exit: Exit Function fnADOSelectFilteredForm_Error: Select Case Err Case Else fnErr "modODBC->fnADOSelectFilteredForm", True End Select If Not rsADO Is Nothing Then If rsADO.State = adStateOpen Then rsADO.Close Set rsADO = Nothing End If fnCloseODBCConnection Resume fnADOSelectFilteredForm_Exit End Function "fnADOSelectCommon" returns an ADO recordset with the SQL string and "fnCloseODBCConnection" closes a global defined ADO connection used in the "fnADOSelectCommon" function. "strADOSQLString" is a global defined string in the module which returns the SQL string this function creates. Cheers, Christian |
|
|
|
Apr 9 2010, 09:09 AM
Post
#3
|
|
|
UtterAccess Enthusiast Posts: 56 |
Christian:
This is excellent. I'm going to give it a whirl. Thank you so much for your help. Hi, the problem with filters in Access is that unfortunately the Access programmers didn't think about the filter syntax. The filter syntax is the same like before, like used in ACCDB/MDB in the Jet style and so it doesn't work as WHERE clause. I had the same problem before. Access handles it internally to convert the filters into SQL syntax but there is no way to get this converted filter. I can only recommend to use filters carefully in Access ADP, they often causes crashes, especially in continous forms with a lot records (>10000). I use the following functions of my ADO library to solve this problem. The first one converts the most common filters of Access into the SQL Server style (fnErr is a function to display an error message). The more complicated filters like "first quarter of year" of a date field are not supported with this: CODE ' Converts a form filter created in Acces into a format which is usable as WHERE clause ' for SQL Server ' Filters with other functions like "DatePart", "Year" and so on are not supported by ADO ' For more infos look here: http://msdn.microsoft.com/en-us/library/ms676691%28VS.85%29.aspx Public Function fnSQLConvertFilter(frm As Form) As String Dim strFilter As Variant Dim strField As String Dim strValue1 As String Dim strValue2 As String Dim lngPos As Long Dim lngPos2 As Long strADOErr = "OK" On Error GoTo fnSQLConvertFilter_Error strFilter = frm.Filter If Nz(strFilter) = "" Then fnSQLConvertFilter = "" Exit Function End If strFilter = Replace(strFilter, "[" & frm.Name & "].", "") strFilter = Replace(strFilter, """", "'") strFilter = Replace(strFilter, "#", "'") strFilter = Replace(strFilter, "Date()", "GetDate()") strFilter = Replace(strFilter, "Now()", "GetDate()") strFilter = Replace(strFilter, "True", "1") strFilter = Replace(strFilter, "False", "0") strFilter = Replace(strFilter, "*", "%") strFilter = Replace(strFilter, "SELECT % ", "SELECT * ") strFilter = Replace(strFilter, " Alike ", " LIKE ") ' -------- ' Replace a "BETWEEN"-Filter with ">=" and "<=" lngPos = InStr(strFilter, "BETWEEN") If lngPos > 0 Then strField = Trim(Mid(strFilter, InStrRev(strFilter, "[", lngPos), InStrRev(strFilter, "]", lngPos) - InStrRev(strFilter, "[", lngPos) + 1)) strFilter = Left(strFilter, lngPos - 1) & Replace(strFilter, "BETWEEN", " >= ", lngPos, 1) strFilter = Left(strFilter, lngPos - 1) & Replace(strFilter, " AND ", " AND " & strField & " <= ", lngPos, 1) End If strFilter = Replace(strFilter, "%53", "") ' -------- ' ADO recordsets sends an error if "LIKE '%xxx'" is used. ' This exchanges the "LIKE '%xxx'" to "LIKE '%xxx%'" (second "%" at the end) ' to avoid the error. lngPos = 1 Do lngPos = InStr(lngPos, strFilter, "LIKE '%") If lngPos > 0 Then lngPos2 = InStr(lngPos + 6, strFilter, "'") If Mid(strFilter, lngPos2 - 1, 1) <> "%" Then strFilter = Left(strFilter, lngPos2 - 1) & "%" & Right(strFilter, Len(strFilter) - lngPos2 + 1) End If lngPos = lngPos2 End If Loop Until lngPos = 0 fnSQLConvertFilter = strFilter fnSQLConvertFilter_Exit: Exit Function fnSQLConvertFilter_Error: strADOErr = "ERROR" Select Case Err Case Else fnErr "modODBC->fnSQLConvertFilter", True Resume fnSQLConvertFilter_Exit End Select End Function The next function uses the above one to get back a recordset containing the filtered records or a SQL string containing the needed command to get these records: CODE ' fnADOSelectFilteredForm ' Date: 28.08.2009 ' ' Returns the same records which are displayed in a form in an Access ADP ' filtered by any sort of user defined filter ' ' The RecordSource of the form should have the following structure: ' "SELECT Whatever FROM MyTable WHERE FormCondition ORDER BY FormOrder" ' ' GROUP and HAVING clauses are not supported. ' Public Function fnADOSelectFilteredForm(frm As Form, Optional strAddWhere As String = "", _ Optional intLockType As ADODB.LockTypeEnum = adLockReadOnly, _ Optional intOpenMode As ADODB.CursorTypeEnum = adOpenStatic, _ Optional intReturnAs As enmADOReturnAs = enmADOReturnAsRecordset) As ADODB.Recordset Dim rsADO As ADODB.Recordset Dim strSQL As String Dim strOrderBy As String Dim strWhere As String Dim strFilter As String Dim strServerFilter As String Dim strWhereWord As String Dim strSchema As String Dim strIDs As String On Error GoTo fnADOSelectFilteredForm_Error Set rsADO = frm.Recordset.Clone strSQL = rsADO.Source ' stored procedure was used, no SQL string possible If Left(UCase(strSQL), 4) = "EXEC" Then ' get the user defined filter of the form and convert it to SQL server syntax strFilter = fnSQLConvertFilter(frm) If strAddWhere <> "" Then strFilter = strFilter & " AND (" & strAddWhere & ") " If frm.ServerFilter <> "" Then strFilter = strFilter & " AND (" & frm.ServerFilter & ") " ' set the same filter as used in the form to the copy of the recordset rsADO.Filter = strFilter Set fnADOSelectFilteredForm = rsADO GoTo fnADOSelectFilteredForm_Exit ' ------------> End If ' Neither SELECT nor EXE then a direct table was entered as RecordSource of the form If Left(UCase(strSQL), 6) <> "SELECT" And Left(UCase(strSQL), 4) <> "EXEC" Then If frm.RecordSourceQualifier = Left(strSQL, Len(frm.RecordSourceQualifier)) Then strSchema = "[" & frm.RecordSourceQualifier & "]." strSQL = Right(strSQL, Len(strSQL) - Len(frm.RecordSourceQualifier) - 1) End If strSQL = "SELECT * FROM " & strSchema & strSQL If frm.OrderByOnLoad = True And Nz(frm.OrderBy) <> "" Then strSQL = strSQL & " ORDER BY " & frm.OrderBy End If End If If InStrRev(UCase(strSQL), "ORDER BY") > 0 Then strOrderBy = Trim(Right(strSQL, Len(strSQL) - InStrRev(UCase(strSQL), "ORDER BY") + 1)) strSQL = Trim(Left(strSQL, Len(strSQL) - Len(strOrderBy))) Else strOrderBy = "" End If If InStrRev(UCase(strSQL), "WHERE") > 0 Then strWhere = Trim(Right(strSQL, Len(strSQL) - InStrRev(UCase(strSQL), "WHERE") + 1)) strSQL = Trim(Left(strSQL, Len(strSQL) - Len(strWhere))) strWhere = " (" & Trim(Right(strWhere, Len(strWhere) - 5)) & ") " Else strWhere = "" End If If frm.ServerFilter <> "" Then strServerFilter = " (" & frm.ServerFilter & ") " End If strFilter = fnSQLConvertFilter(frm) If strFilter <> "" Then If frm.FilterOn = True Then strFilter = " (" & strFilter & ") " Else strFilter = "" End If End If If strWhere <> "" Or strAddWhere <> "" Or strServerFilter <> "" Or strFilter <> "" Then strWhereWord = " WHERE " Else strWhereWord = " " End If If strAddWhere <> "" Then strAddWhere = " (" & strAddWhere & ") " strWhere = IIf(strWhere <> "", strWhere, "") & _ IIf(strFilter <> "", " AND " & strFilter, "") & _ IIf(strServerFilter <> "", " AND " & strServerFilter, "") & _ IIf(strAddWhere <> "", " AND " & strAddWhere, "") If Left(strWhere, 5) = " AND " Then strWhere = Right(strWhere, Len(strWhere) - 5) strSQL = strSQL & strWhereWord & " " & strWhere & " " & IIf(strOrderBy <> "", strOrderBy, "") Select Case intReturnAs Case enmADOReturnAsRecordset Set fnADOSelectFilteredForm = fnADOSelectCommon(strSQL, intLockType, intOpenMode) Case enmADOReturnAsSQLString Set fnADOSelectFilteredForm = Nothing End Select strADOSQLString = strSQL fnADOSelectFilteredForm_Exit: Exit Function fnADOSelectFilteredForm_Error: Select Case Err Case Else fnErr "modODBC->fnADOSelectFilteredForm", True End Select If Not rsADO Is Nothing Then If rsADO.State = adStateOpen Then rsADO.Close Set rsADO = Nothing End If fnCloseODBCConnection Resume fnADOSelectFilteredForm_Exit End Function "fnADOSelectCommon" returns an ADO recordset with the SQL string and "fnCloseODBCConnection" closes a global defined ADO connection used in the "fnADOSelectCommon" function. "strADOSQLString" is a global defined string in the module which returns the SQL string this function creates. Cheers, Christian |
|
|
|
![]() ![]() |
|
Go to Top · Lo-Fi Version | Time is now: 22nd May 2013 - 09:54 AM |