MS Access Forum / Queries / February 2008
Allen Browne's Filter - Modification troubles
|
|
Thread rating:  |
markmarko - 21 Feb 2008 23:13 GMT I have built a filtering system for our sales order modeled after Allen Browne's Search procedure (http://www.allenbrowne.com/ser-62.html).
Some of the criteria are applied to the forms filter, and others to the forms recordsource.
I originally made a handful of queries and based on criteria, the code selected the correct query for the recordsource. I'm going to have more options, so I decided it would be better to just have the code 'build' an sql statement for the recordsource.
I'm having a problem creating the sql expression. But first I need to find out how to apply it...
Is it possible to make a form's recordsource an sql statement? If not, if I make a query the recordsource, can I programatically change the sql?
Jeanette Cunningham - 21 Feb 2008 23:27 GMT Hi, you can go Dim strSQL as String strSQL = "SELECT . . ." Me.RecordSource = strSQL
the above sets the forms recordsource you can programmatically change the sql and then you just go Me.RecordSource = strSQL again
Jeanette Cunningham
>I have built a filtering system for our sales order modeled after Allen > Browne's Search procedure (http://www.allenbrowne.com/ser-62.html). [quoted text clipped - 14 lines] > I > make a query the recordsource, can I programatically change the sql? markmarko - 22 Feb 2008 00:14 GMT Thanks Jeanette,
I was hoping that was possible... I tested putting an sql statement (copied from a query) in the recordsource property directly, and it crashed access. So, I'll take your word for it that vba can do it.
Now on to the tricky part.... In order to 'filter' by Salesperson (Salesperson is related to Sales Order via a junction table, since a Sales Order may have more than one Salesperson). Here's the sql:
SELECT [Record-Orders-Sales].*, [Query-Junction-Cust_Account].*, [Junction-SalesOrder_Contractors].AssociatedContractorID FROM ([Record-Orders-Sales] INNER JOIN [Query-Junction-Cust_Account] ON [Record-Orders-Sales].[AssociatedCustAcct#Junction] = [Query-Junction-Cust_Account].JunctionID) INNER JOIN [Junction-SalesOrder_Contractors] ON [Record-Orders-Sales].SalesOrderID = [Junction-SalesOrder_Contractors].AssociatedSalesOrderID WHERE ((([Junction-SalesOrder_Contractors].AssociatedContractorID)=[Forms]![Entry-SalesOrder]![Filter-SalesRep1])) ORDER BY [Record-Orders-Sales].SalesOrderID;
In order to filter by 2 sales peeps, I'd want to add to the string ala Allen Browne's filter model, but the a bit I'd need to add would be 'injected' into the above sql, not at the end.
Here's what the sql would look like for filter by 2 sales peeps, (again, from a query (that works)). SELECT [Record-Orders-Sales].*, [Query-Junction-Cust_Account].*, [Junction-SalesOrder_Contractors].AssociatedContractorID, [Junction-SalesOrder_Contractors_1].AssociatedContractorID FROM ([Junction-SalesOrder_Contractors] AS [Junction-SalesOrder_Contractors_1] INNER JOIN ([Record-Orders-Sales] INNER JOIN [Query-Junction-Cust_Account] ON [Record-Orders-Sales].[AssociatedCustAcct#Junction] = [Query-Junction-Cust_Account].JunctionID) ON [Junction-SalesOrder_Contractors_1].AssociatedSalesOrderID = [Record-Orders-Sales].SalesOrderID) INNER JOIN [Junction-SalesOrder_Contractors] ON [Record-Orders-Sales].SalesOrderID = [Junction-SalesOrder_Contractors].AssociatedSalesOrderID WHERE ((([Junction-SalesOrder_Contractors].AssociatedContractorID)=[Forms]![Entry-SalesOrder]![Filter-SalesRep1]) AND (([Junction-SalesOrder_Contractors_1].AssociatedContractorID)=[Forms]![Entry-SalesOrder]![Filter-SalesRep2])) ORDER BY [Record-Orders-Sales].SalesOrderID;
It's the same as the first version, with the [Junction-SalesOrder_Contractors_1] bits added. The trick is that it's added kind of in the middle. For this one instance, I'm sure I could make it work, but I want to make a model that I could scale to allow building the recordsource sql to include other factors, and need a systematic way to add to the sqlString.
Any advice?
Allen Browne - 22 Feb 2008 01:30 GMT Open the form in design view Open the properties box to look at the properties of the form. Click in the RecordSource property (Data tab.) Click the Build button (...) beside this. Access opens the query builder, so you can build the SQL statement. (If the RecordSource was a saved query it opens that. If it was a table, it asks if you want to build a query instead.) Behind the scenes, it saves this as a hidden query anyway, but it does work as a SQL statement.
If it crashed Access, then something else is wrong. Perhaps you tried to do this in Form view (not design view.) Perhaps you omitted a field: Access can crash if a field suddenly disappears or changes data type while the form is open. Or perhaps it's a Name AutoCorrect error: http://allenbrowne.com/bug-03.html Or it could be a corrupt form. (Try a compact/repair.)
Once you have this working, your next question was about how to programmatically change the RecordSource while the form is running. You don't want to change the stub of the SQL statement (the SELECT and FROM clauses), and probably not the tail either (ORDER BY, GROUP BY, etc.) Therefore you just need to patch in the WHERE clause between the stub and the tail. The code to do that looks like this: Dim strWhere As String Const strcStub = "SELECT [Record-Orders-Sales].*, ... FROM ... " & vbCrLf Const strcTail = "ORDER BY [Record-Orders-Sales].SalesOrderID;"
'Save any changes in progress If Me.Dirty Then Me.Dirty = False 'Build the filter string as shown in the example database. strWhere = "WHERE SomeField = 999 " & vbCrLf 'Now assign this to the form's RecordSource Me.RecordSource = strcStub & strWhere & strcTail
Since you now have 2 techniques, the final question is which is better? To apply a Filter, or to change the RecordSource? There are specific cases where each is useful, but as a rule of thumb for starting out, apply a filter if you want the user to be able to remove the filter easily, and change the RecordSource if the user should not be able to get at the other records, or if there are performance reasons for not loading the other records.
 Signature Allen Browne - Microsoft MVP. Perth, Western Australia Tips for Access users - http://allenbrowne.com/tips.html Reply to group, rather than allenbrowne at mvps dot org.
> Thanks Jeanette, > [quoted text clipped - 58 lines] > > Any advice? markmarko - 25 Feb 2008 17:11 GMT Regarding using recrodsource, some of my criteria are on a continuous subform, and as I understand it, this means I cannot simply filter on that criteria.
I'll explain the scenario more fully...
The main form is a Sales Order, and the subform indicates which Sales Reps made the sale. Sales Reps are connected to the order via a junction table, since there may be 1 or 2 Reps on a Sales Order.
I'd like the user to be able to filter by 1 or 2 reps, using 2 unbound combo boxes.
As I mentioned, I had built queries originally. The queries for filter by 1 rep was different from filtering by 2 in the SELECT clause, the FROM clause, and the WHERE clause. Basically, it references a 'copy' of the SalesRep Junction (Same table name followed by '_1'.
Is that needed? Is there a way to filter by 2 reps without that 'copy' table reference?
Also, in your example, is '999' a placeholder? And why is the vbCrlLf needed?
Allen Browne - 26 Feb 2008 03:48 GMT Replies in-line
 Signature Allen Browne - Microsoft MVP. Perth, Western Australia Tips for Access users - http://allenbrowne.com/tips.html Reply to group, rather than allenbrowne at mvps dot org.
> Regarding using recrodsource, some of my criteria are on a continuous > subform, and as I understand it, this means I cannot simply filter on that > criteria. No, that's not correct. You can filter a continuous form, and you can change the RecordSource of a continuous form.
> I'll explain the scenario more fully... > [quoted text clipped - 6 lines] > combo > boxes. So one [Sales Order] can be shared by multiple [Sales Reps]. I take it you have a main form bound to the [Sales Order] table, with a subform bound to a related table where you enter the sales resps for that order, one per row.
If so, you can filter the main form so it shows only the sales orders where a particular rep was invovled like this: Filter a Form on a Field in a Subform at: http://allenbrowne.com/ser-28.html
To filter by multiple reps, you would need to be clear about whether you want only sales where *both* reps were involved (an AND), or sales where *either* rep was involved (an OR.) Either way, you will end up using a subquery to achieve that. If subqueries are new, here's a starting point: http://allenbrowne.com/subquery-01.html
> As I mentioned, I had built queries originally. The queries for filter by > 1 [quoted text clipped - 6 lines] > table > reference? I'm not sure of the context here, but it seems like you have 2 copies of hte same table in your query? A subquery would need to alias the table.
> Also, in your example, is '999' a placeholder? And why is the vbCrlLf > needed? Yes: it's an example.
The carriage return/line feed is not needed; it just makes the SQL statement more readable when you are trying to debug it.
markmarko - 27 Feb 2008 23:26 GMT Thank you very kindly. Those subqueries are exactly what I was needing!
markmarko - 28 Feb 2008 17:01 GMT So, what I've ended up doing is to have all filter criteria concatenate into the WHERE clause, instead of some going into the 'filter' and others going to WHERE of the recordsource. This greatly simplifies my code.
|
|
|