Work-around for 255 character WHERE clause limit in Access 2010 Web database macro? - sharepoint-2010

I'm creating a web application using the 2010 Access Services SharePoint 2010 publication tools.
I am currently creating a reporting page where the user can toggle multiple drop-down menus to filter the results of a report. The problem is, the WHERE clause filter in the macro editor has a 255 character limit, which allows me to only apply 3 WHERE criteria, (and I need to employ ~8 criteria). Does anyone have a work-around for this problem where I can perhaps nest multiple dynamic WHERE clauses or something? I've already employed aliases to make the condition statement about as short as possible. It currently reads as:
BrowseTo
Object Type: Report
Object Name: rptSA_Report
Path to Subform Control: frmMainMenu.NavigationSubForm>frmQueryFilters.subrMaster
Where Condition: ([TempVars]![SF] Is Null Or [SF]=[TempVars]![SF]) And ([TempVars]![P] Is Null Or [P1]=[TempVars]![P] Or [P2]=[TempVars]![P]) And ([TempVars]![PA] Is Null Or [PA1]=[TempVars]![PA] Or [PA2]=[TempVars]![PA])
Page:
Data Mode: Read Only
I'm aware that there are a ton of limitations with the Access/SharePoint Web Services, but I'm hoping someone has a functional work-around for this issue in particular.
I've already tried building a string temporary variable and using that in the WHERE clause, but the report wouldn't recognize the parameters when they're buried in a string variable.

Related

Read/Write SQL Server views in MS Access using SCHEMABINDING

I am having to redevelop an MS Access 2003/2010 ADP project, that uses SQL Server views as the RecordSource for all its forms, into an MS Access 2016 ACCDB.
I have tried using pass through queries to get the data and this works fine for readonly columns, however when I want to change the value in one of the bound columns, it says that the RecordSet is not updateable, which is what you might expect if using a view.
But I have now read that if you define the view with SCHEMABINDING like this:
ALTER VIEW [dbo].[vwQuote_MinibusesDetails]
WITH SCHEMABINDING
AS
SELECT ...
and add a UNIQUE CLUSTERED INDEX like this:
CREATE UNIQUE CLUSTERED INDEX CIX_vwQuote_MinibusesDetails
ON vwQuote_MinibusesDetails (txtQuoteNo, txtVersion, txtVehicleNo);
and then add the view to your project as a DSN-less TableDef like this
stConnect = "ODBC;Driver=SQL Server;Server=" & SERVER_NAME & ";Database=" & APP_DATABASE & ";Trusted_Connection=Yes"
Set td = CurrentDb.CreateTableDef(stLocalTableName, dbAttachSavePWD, stRemoteTableName, stConnect)
CurrentDb.TableDefs.Append td
it becomes editable as if it were a table.
However, when I open the TableDef in Access it shows all the rows and columns as if it were editable, but if I try to edit a column, it says that there is a Write Conflict with another user's changes, when I am 100% sure that there isn't because I am the only person using it.
Any ideas? (I am using Access 2010 at the moment)
But why do all that truckloads of work? There is zero reason to do all that extra work.
Simply bind and set the forms data source to a view. It is assumed that you will simply link all of the existing views on the client side. Access will thus see all the views as simply tables, and views (as opposed to Pass through queries) are read/write.
So, there is no need to:
Have ANY connection strings in your code. If you ARE using connection strings in code, then you approach is all wrong. Just link to the views, and set the forms data source as that view.
At this point, the forms can edit data.
As for a pass-through quires to drive combo boxes? Do NOT do this. While a PT query is likely the fastest way to pull data, the access client cannot filter PT queries. So you ONLY EVER want to use a PT query for cases in which the client side does NOT have to filter the results. If you bind a combo box to a PT query, then Access needs and wants to ONLY pull the one value from that table for display. And since the access client can’t filter a PT query, then it will scan the WHOLE data source for that combo box to get the one value that is currently displayed. If you use a linked table (or even a view) to that source that drives the combo box, then the access client can filter that dataset to the ONE row. So, do NOT use a PT query for ANY case in which client side filtering is required. A linked view (or linked table) is fine in these cases.
So, just bind the forms directly to the linked table, or the linked view.
If the table has 1 million rows of data, and you say do this:
Docmd.OpenForm "frmInvoice",,,"InvoiceNum = 1234"
Access will open the form to the ONE row of data, and ONLY pull one row down the network pipe. This is despite that the form in question is bound to a table of 1 million rows. The form will load instant, and you not had to write any sql, any connection stuff, and not really do anything different then how you developed typical access applications.
Bound forms are how and why Access saves huge development dollars. If you jump to .net, then you have all kinds of tools and wizards that can help you around this issue. So in .net, you could adopt the dataset designer, or use the newer entity framework.
In Access, we don’t have this huge tool box of data designers and tools, so if you attempt to hand code, and code up the data sources for a form, then you get the worst possible outcome (you write truckloads of code, and don’t have all those cool tools for un-bound forms).
Simply link your forms to linked tables (or views) and you now have a working data bound form without any code. If you need to load the form, then use the 20+ year standard approach of the “where” clause of the open form command to open the form to the one record. The access client will ONLY pull what you put in the “where” clause.
So, to wire up a form for editing of data, ZERO code is required. The only developer efforts will then to ensure that the form does not pull un-necessary data to the client.

Placing an undeclared variable in SQL query code generates an input box?

I recently posted this answer as a way to get user input when creating a MS Access query or report. The general behaviour is that if an undeclared variable is placed in SQL query code or a report (e.g. [UndeclaredVariable]), a small input/dialog box appears for the user to input the variables value.
I have been unable to find any mention of this functionality in documentation or elsewhere. All discussion is about using InputBox() in the standard way.
This functionality is unexpected/unusual for several reasons:
(In my limited knowledge) Using undeclared variables in MS Access generally causes an error
The input/dialog box is different than the one created when InputBox() is used
The functionality seems to transcend standard behavior (e.g. when an two undeclared variable are used in this way as the "ifTrue" and "ifFalse" components of an IIf() statement, BOTH dialog boxes are created sequentially!)
Does anyone know what this functionality is called or why it works in these ways?
To summarize the above comments:
the behavior is called a "parameter query" and is like normal parameterized queries (see here)
The behavior with IIf() is because Access requires a parameter to be given whether or not the value is used (in this case for both [ifTrue] and [ifFalse])
There seems to be no way to conditionally parameterize a query or report
Ok, as to why they work the way they do? Well a lot of people use Access for just working with data tables. They don't necessary build forms and reports. So, if you place a [parm] box in a query, it will prompt you, and you don't need code. So, a really handy feature.
And of course if you do build a report, and need a quick and dirty way to prompt for some criteria then once again, super handy, and again no code or forms need be written.
And if you do create a form, then you can place criteria in a query like this:
select * from tblCustomers where City = Forms!MyPromptForm!City
once again, no code. And using a forms! expression like above means no prompt when you run the query (or a report based on that query).
The only real downside of using these parameters is they are not without effort to make them optional.
As you are finding out, putting forms! expression in queries can get really messy real fast. And such queries can prompt you when you don't want to.
Even worse, is now that the query is now "married" and attached to that ONE form (if you use forms! expressions for parameters). Often, I have a nice query that I could use MANY times for different reports, and often even that same query could be used for reports...but then someone comes along and puts in a expression or paramter(s) that means the query is ONLY good when that form is opened, or you get nasty prompts for some parameter that you now don't want. Or you want DIFFERENT criteria on a different column.
So hard coding the number of parameters in such a query is REALLY painful, not flexible, and really starts to fall down.
So, if you have 5 combo boxes on a form, but the user only selects restrictions in 3 of the combo boxes...and wants the other 2 to be ignored?
I could probably write another 10 or pages as to why putting forms expressions in queries or shoving in parameters is bad (besides...it makes the queries real ugly, and hard to read. and, the sql then is not standard anymore (it will not work with server based systems either).
So, the solution use now is simply to take the values from the form, and build your own where clause in code. That way, you simply design the reports (or forms), and attached them to the query, BUT NO FORMS! conditions are placed in the query. And the SQL is clean without garbage in it.
To "send" the conditions to the report (or form), you simply use the "where" clause. This is exactly why ms-access has this feature…and it solves a zillion problems…and will reduce your development costs by a substantial amount.
Take a look at the following screen shots to see what I mean:
So in above we have a start date, and end date. And the user can select 1, or several tours and THEN click on the report view button. Trying to deal with a easy and clean "prompt" form for user and THEN attempt to use a query with parmaters is sheer folly.
The code to make those above screens work and launch the report with the selected restrictions when you hit the "print" button is easy:
Or take this screen:
So in the above we have a combo box to select the sales rep.
But, you can leave it blank.
So, code to deal with above will work like this:
dim strWhere as string
'select sales rep combo
if isnull(cboSalesRep) = false then
strWhere = "SalesRep = " & cboSalesRep & ""
end if
' select "status" for the report
if isnull(lstStatus) = false then
if strWhere <> "" then
strWhere = strWhere " and "
end if
strWhere = strWhere & "Status = '" & litStatus & "'"
end if
Note how the 2nd list box is checked for a value. You can add as "many" more conditions you want. Lets say we have a check box to only include Special Customers. We can add to our very nice prompt screen a check box to
[x] Show Only Special customers
The code we add would be:
if chkSpeicalOnly = True then
if strWhere <> "" then
strWhere = strWhere " and "
endif
strWhere = strWhere & "SpecialCust = true"
end if
For sure, each combo and control we add to the nice report screen takes a bit of code, but no more messy then the query builder..and this way, each query is nice and clean, and free of a bunch of HIGHLY un-maintainable forms! expressions or "optional" paramters.
Further, it means you can re-use the same query for different reports, and have no worries about some form that is supposed to be open or some nasty out of the blue prompt for a parameter. So, a tiny bit more code eliminates the messy query problem.. For me, this is very worth while trade.
So parameters are quick and dirty. But if REALLY going to start building a decent user interface and some nice report prompt forms? Dump the use of parameters - you be glad you did. And you only have to go to the ONE code spot, add another code block for a new and optional critera. You don't have to change the report, and and you don't have to go and modify the SQL either. So, a bit of code goes a LONG way to attacking this problem.
At the end of your code, we now have a valid SQL where clause. So, now just launch the report with with this:
Docmd.OpenReport "ReportName",acViewPreview,,strWhere
And the above also works for searching and launching a form. So the form can be based on such queries, and again no prompts or paramters means the form can be used to edit that data.
So the concept of filter data and launching forms (or reports) can and should be detached from the concept of some query that pulls data from a table. Over time, software will change, and then the boss will ask how about a filter or prompt for invoice number, but that again has to be optional. Over time your business rules will change. And you can often apply that filter to "many" reports. So in this form, the critea is built up, but the list box allows you to select one of "many" reports, and not all are based on the same SQL, but they all accept the same "filter" or better term used is the "where" clause of the open report or form command.
In above, the user can hold down the ctrl-key to select 1 or 2 or hit the "select all" button. In that form, the user is actually selecting the bus tour ID for a given tour. And then they can choose the report in the lower left. Again, attempting to acheive the above multiple critera simply can't work with sql paramets anyway.
I am using a TourID = some value and Busid in (LIST OF buses selected).
once again, you can simply pass that complex "where" clause to the report - and that where clause can even have a sub-query, or a Field in (LIST OF ID'S) criteria (which can't be done with parameters anyway).

How can I create a (server-side) filtered editable SQL recordset for Microsoft Access?

I am working on a very complex legacy ADP project in Microsoft Access that connects to a 2008 SQL Server back end. A common usage scenario is a form in datasheet view that contains an editable recordset.
The approach used through most of the database is to load the form, then build the SQL dynamically in VBA using form parameters, and apply the SQL as the RecordSource for the form. Many of the queries are quite complex, so this makes for really ugly code and a maintenance nightmare.
For the read-only recordsets, I have converted the dynamic sql to parameterized stored proceedures, which works great. Nice and clean, and easy to maintain going forward.
But for the editable recordsets, I am trying to determine the best approach:
1. Dynamic SQL - As mentioned above, I would really like to avoid this approach.
2. SQL View - The challenge here is that some of the tables are very large, so if I try to load the view and then filter it on the form, it has to pull the entire recordset from the SQL server, even though I only need a small number of rows. (Negative performance and IO impact.)
3. Use context_info - This sounds intriguing, but does not sound like a recommended approach based on discussion here: Create parameterized VIEW in SQL Server 2008 If I was developing against SQL Server 2016 I might look more into SESSION_CONTEXT.
4. Parameter Table with View - This is an idea that I am leaning towards. I would create a Parameters table in SQL, and set the parameter value (as a key/value pair) with the session ID. The view would then filter based on the current value in the parameter table. This would allow me to use a view as my RecordSource to support the edits, but the filtering would take place on the SQL Server side.
Is the parameter table indeed the best approach to take with this project, or is there another way that I could access a parameterized read-write recordset that is filtered on the server side?
I assume you talking about a non adp project now.
Even if you don’t use a view, and say bind a form directly to a linked table of 1 million rows, then access will ONLY pull down the records you requests. You simply just use the forms “where” clause of the open Form command.
So you don’t even have to use dynamic sql here.
However, you don’t want to launch a form bound to large table UNLESS you set the where clause.
You can certainly open a form without a reordsource, have the user enter some parameter values into a text box, and then go:
Dim strSQL as string
strSQL = "select * from tblCustomers where InvoiceNum = " & me.MyInvoiceTextBox
Me.RecordSoruce = strSQL
However, in most cases you better to create some type of search form. Let the user enter some values, display the results like this:
So in above, the person type in "smi". You display the results
(and in above I did use the above approach of stuffing the sql directly into the forms reocrdsource
Now on the edit buttons along the side to launch + edit one record,
I simply go:
Docmd.OpenForm "frmCustomer",,,id = & me!id
Once again, EVEN if the form is bound directly to the linked SQL server table, only the ONE record will be pulled from SQL server. So no messing with sql, no messing with parameters etc. is required.
So a regular non ADP access application with linked tables DOES NOT pull the whole table.
You can also after opening a form set the forms filter – and again access will ONLY pull the reocrds in question from the linked sql table. It is a “common” myth that access pulls all records – it does not if you provide a filter, and I recommend you open a form to one record, let the user work then close the form and return back to some search screen in which you ready to do battle with the next customer etc.
so provide a search form - don't recommend having the form to edit data be all cluttered up with the ability to search records. Let the user edit, and then close the form - this also promotes the record being saved after the user done working.
edit:
For a form that has any kind of complex joins etc., then create a view, and bind the form to that view. You use the forms "where" clause, then once again access will only pull down the one record. So for complex joins etc., yes access can often mess that query up and it runs slow. So if the form is bound to one table (that is MOST cases), then bind the form directly to the linked table. If the sql is complex, then bind the form to the linked view, and as noted in either case ALWAYS provide a "where clause" to the openform command - it will in these cases ONLY pull the one record into the form. And once again, no messy parameters, no messy sql is required on the access side - you will save MASSIVE amounts of coding if you adopt this approach, and you also get stellar performance since you limiting the reocrds pulled into that form from sql server.

import data from .txt for reporting purposes

I am running a query in Report builder that uses order numbers (approx. 100). Currently they are fixed and I have to change them each time. Is there a way that I can import those numbers to Report Builder in .txt and then run the report.
The query is like the following:
Select * from purchase p
where p.order in ('15642','1245','623565')
This is a simple query but my query has lots of joins
If not, how can I rewrite this report so that users can choose their own order number?
Does Cyrstal report have that ability?
Making a .Net/C# application Tool and export results to EXCEL??
Suggestions would be appreciated!
Yes, Crystal Reports can import from textfiles (At least Crystal Reports XI that I'm using), although that functionality might not be installed by default.
Create a new connection, choose "Access/Excel (DAO)". In the dialog that comes up, select "Text" as database type. By default the first line of the text file is supposed to be headers. I don't know if it is possible to change this behaviour.
As for letting users choose the order number at runtime that is precicely what parameters are for. Create a parameter and call it like {CR_test_txt.TEST0001} = {?myParameter} in the field selection expert. Depending on your report and advanced runtime options you want you might have to parse the parameter before using it.

ms access - use function in criteria section

I would like to use a function in the criteria section of my access table. Is this possible? I want to make the criteria area dynamic, so I thought if I add a function from a module it could work.
Yes you can use a user function (or any other VBA function) in the criteria of your queries. Just be mindful of the fact that it will pull the data down locally to do the filtering work so if that is your only filter criteria and you are querying a large table over a network you might run into problems