Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 11 months ago.
Improve this question
My question: Why would a SQL string function properly as a query but not as the RecordSource of a report?
I apologize for the lengthy background, but I think the context in which this issue is arising is probably helpful. In Access 2019, I have a MainQuery that is based upon multiple other queries, some of which are parameter queries. So, MainQuery itself does not contain any parameters as part of its definition, but because its "constituent queries" contain parameters for which the user is prompted, running MainQuery prompts the user for said parameter values. Note that I call them "constituent queries" because they are all standalone query objects in my database as opposed to true subqueries within MainQuery.
MainQuery is the RecordSource of MainReport. Of course, upon opening MainReport, the user is prompted for the parameters that allow MainQuery (i.e. all its constituent queries) to run. Naturally, the user must reopen or refresh MainReport and supply different parameter values each time to see a different set of data inside MainReport.
This arrangement has worked well for years and continues to work, but I recently decided I wanted to increase the functionality of the database by allowing the user to print out multiple MainReport reports (for different records) in rapid succession.
The strategy I used was to consolidate MainQuery and all of its constituent queries into one big, complex MasterQuery made up of legitimate subqueries defined inside of it. The parameters for which the user used to be prompted each time the MainQuery was run were replaced with a simple string place holder, and the entire body of the MasterQuery is saved in a SQL_Table so that my VBA code can access it. Now, the user can select the records for which he or she wishes to print on a form designed for this purpose. Then, upon clicking a button, my VBA code gathers the user's choices, retrieves the template SQL string from the SQL_Table, and for each record that the user wants to print, replaces the string place holders in the SQL string (previously known as the parameters) and assigns the RecordSource of MainReport to that SQL string.
As I was working on this project for the last week or so, I was able to get this process to work very beautifully and successfully. But, as I continued developing it, I ended up making several additions and alterations to the MainReport and MasterQuery to improve the functionality of the database.
So, the current state of affairs is that I am successfully passing the SQL string to the RecordSource property of the report, but the problem is that Access tells me there is an error in the SQL string, and it will not actually run the report. Instead, the report stays in DesignMode and will not go into Report View. The error message says,
Syntax error in query. Incomplete query clause
In attempting to diagnose the problem, I took the exact same SQL string (I literally copied and pasted it from the RecordSource property of report into the SQL View of a blank query), and to my surprise, the query runs beautifully. It returns the result set that I expect to see. As a bonus, I even saved the query as Query1 and set the RecordSource of MainReport to Query1, and even this works!
I don't understand this behavior. I might expect that either they both work with the same SQL string or they both don't work, but I don't understand why they might behave differently; and this is the crux of my question.
So, why would a SQL string function properly as a query but not as the RecordSource of a report?
Thanks in advance for anyone who might have any ideas!
Well, since the query in its raw form will not run, and you fully pointed out that you "replace values in that query?
And since you ALSO point out that you are replacing the reports query source (and you MIGHT WANT to show and explain how you doing that?
So, given that you EACH TIME are going to modify the raw query? Then obvislity if you modify it for one time, then the values in that report (the critera) will have be changed. So, it ALSO not clear how you deal with that issue??
In most cases, becuase the query in its raw format has "values" that you going to replace, then in theory those values need to be "known" so you can repalce them.
Thus, as a general apporach for the above?
I save the raw query in the querybuilder, but then MAKE A COPY of that query, make the critera replacments and then SAVE that query to a 2nd query - a query that the report is based on.
So, say we have a simple query and report.
qryHotelsS (I put a "s" on such querys - means "source"
qryHotels (the final fixed up and changed query).
So, say I have this:
SELECT * FROM tblHotels WHERE City = '#City' ORDER BY HotelName.
So, I now might have some really nice prompt form, or form that allows the person to enter the city criteria, and then hit a view report button.
The code would thus look like this:
Dim strSQL As String
Dim strCity As String ' for test - the value would no doubt come
' from a very nice form wiht a text box, and
' button to launch the report.
strSQL = CurrentDb.QueryDefs("qryHotelsS").SQL
strCity = "Calgary" ' as noted, this would be some text box value on
' a nice report form
strSQL = Replace(strSQL, "#City", strCity)
CurrentDb.QueryDefs("qryHotels").SQL = strSQL
DoCmd.OpenReport "rptHotels", acViewPreview
So, we grab our "source" query, replace the values we want, and then save the query to a query that the report is based on, and then simple launch that report.
I mean, it really comes down to how your replacing and setting up the query now? The REALLY nice feature of above? You can run the code (comment out the open report command above). Once you run the above code, then you are rather free to open up the report and do further design and tweaking of the report, and since it has a valid query source, then you are free to design, change and setup the report any way you want. (since it has a valid sql query source).
so, adopt the idea of a having two queries for the report. The "source" query - with some values that you replace in VBA code. I just out of the blue used '#City', so I use # signs, and you can roll your own quite much anyway you want. You could even leave in the [] and have your VBA replace the [], but I like using # signs for this. And it works well even for dates.
eg:
WHERE InvoiceDate = ##InvoiceDate#
So, in code, you can just replace #InvoiceDate with a date string, but the delimiters (#) don't need to be added.
Edit: Why some query can't work in code?
Well, if you can take that string, shove it (save it) into a query, and then run the report on that query, then this can work.
However, there is a SIGNFICANT difference to use the DAO object model, and shoving sql into a reocrdset vs that of basing a form, or query on the same source.
Remember, the DAO recordset object does NOT allow and does NOT know about forms! Expressions etc., and they can't be used.
And if you introduce ANY VBA function into the sql? Once again, you cannot use the DAO querydef object.
The pure data engine (DAO) can be used from vb6, vb.net, c# etc. The data engine thus does not allow for example forms! expressions, and it ALSO does not allow use of custom VBA functions in that sql.
So, basing a reprot on a saved query def? No problem, both forms! expresisons, and even VBA functions can be contained in the sql query.
However, if you attempt to use the SAME query, and shove it into a DAO recordset? Then the so called "expression" service. (the system that resolves forms! expresions, and resolves VBA function calls) cannot be used.
That is due to the fact that the data base engine (JET/ACE) does not know about VBA, does not know aobut forms!, and it is a stand alone data engine, and a data engine NOT limited to being used with Access, but as noted can be used from FoxPro, vb.net, c#, vb6 etc. So, a pure DAO data engine call does not have nor allow forms! expressions, and as noted does not even allow you to have VBA expressions. It has to be 100% valid JET ONLY sql syntax. So, while some functions exist in JET sql, a good number of VBA ones are NOT allowed.
The JET database engine thus does NOT even know nor even assume that a forms! object exists, can be open, or closed, and the same goes for VBA functions used in that sql - in fact they can't be used.
So, if you put such expresisons in a query, and use from MS-ACCESS? Then the query can be run from the UI, can be used as a data source to a report, but in pure VBA code, setting the same query to a DAO recordset object will fail.
So, it probably better to either:
Figure out if you have any VBA functions used in the sql
Figure out if you have any forms! expressions used in the sql
And then remove the above.
However, you might have a bit of a difficult time working through that messy sql, so you can then just shove that query string into a querydef ojbect (save it into the .SQL property as I did above), and then simple base the report on that saved query as opposed to trying to create a DAO recordset object in code, and using that for the forms reocrdsource, which as I point out above can't use forms! or VBA functions - and has to be pure valid JET/ACE syntax without such expressions.
I'm trying to TextJoin in Access, I was able to complete this in Excel for a entire row by using the below formula:
=TEXTJOIN("",TRUE,F2:F251)
How do I replicate this in Access?
MS Access uses a completely different paradigm to Excel. There is no way of doing this without handcrafting it in VBA code.
Loop through the recordset rows and concatenate the column values to a variable. You can't really rely on the column order being correct in a for/next loop so you might have to refer to the columns by name.
For a client I have to use MS Access 2007 as a lightweight front-end to SQL Server 2008.
One of the requirements, security-wise, is that I need to fetch my recordset data via stored procedures. I'm doing this via SQLOLEDB, based on tutorials provided here: http://accessexperts.com/blog/2011/07/29/sql-server-stored-procedure-guide-for-microsoft-access-part-1/
I have a mainform with some general data, on which I also set the form recordset (Me.recordset) in the code-behind. At the bottom of the form, there is a subform, with a table of rows of data. This is also an ADO recordset being set in the code. In order to make those subform records editable, I made a extra recordset in which I cloned the data in, then I bound it to the subform's recordset (Me.recordset -> but in context subform). I added a save button after each row in the subform, and via an event I'm doing the writes manually via another stored procedure.
This all works, but I get some very weird behavior when I edit some data in the first row (for example), and then click on a field in another row (for example the second row). Now suddenly all my fields change to '#Name?'; basically my subform gets unbound.
Now I'm not sure how to debug this, let stand fix it. Any help on this error is greatly appreciated.
I forget to put tempRs.ActiveConnection = Nothing
It is working as intended now :)
I'm in the process of converting a MS Access 2000 database to MySQL, while still using Access for the front end.
I've come across a problem where some forms get the data from fields in MS Access tables. IE, the "Control Source" value is set to a specific field, and when the form is run, its creates the required number of Textboxes to match the number of entries in the table and populates them with the data from the tables.
Now I'd like to be able to set the Control Source of the Textbox to call a VBA function, which get's the data from MySQL, and populates the textbox with the entries in MySQL table. I'm not sure how this is achieved, or if its even possible.
So could I just create a VBA function and set it in the Control Source property for the Textbox, or do I need a more complicated solution ?
You do not need any code for the text boxes to display. Simply use a linked table to MySql, and the form should function as before. There is little if any reason I can think of here to dump the use of bound forms and bound controls.
i am new to access and i am debugging someone's database
how do i know if i am using ADO?
i have stuff in a listbox, how do i use the .GetRows method to put the recordset into a two-dimensional array?
Do you have a reference to the ADO libraries (In a code window, under Tools->References: Microsoft ADO Ext x.x For DLL and Security, Microsoft ActiveX Data Objects x.x Library) Have you set the recordset to an ADO recordset?
You will find details of GetRows here: http://www.w3schools.com/ado/met_rs_getrows.asp
You can use it like GetString, as illustrated in a reply to your previous post.
EDIT
You do not have to have a reference to the ADO libraries to use ADO, but it can be easier. To use ADO without the libraries (late binding), try something like:
Dim cn As Object
Dim rs As Object
Set cn=CreateObject("ADODB.Connection")
Set rs=CreateObject("ADODB.Recordset")
cn.Open strConnect ''Any suitable connection string
rs.Open strSQL, cn ''Any suitable SQL string
As others mentioned, to check if the using ADO, you as a general rate ruled can look in your code. However what's probably confusing you and not has been explained is that it's ONLY in your coding practices do you choose ADO or DAO.
For the rest of the application (ie: BUILT IN OBJECTS) you will use the concept of what's called linked tables. These linked tables handle all of the connection strings and all of the internal workings for you. There's no additional effort required on the user's part when they're developing the application. For all of these internal objects, you don't choose a particular data object type (ADO or DAO).
What this means is that for filling data into forms, data into reports, data into listbox, data into combox boxes etc. you DO NOT write code, and YOU DO NOT use connection strings. And you DO NOT HAVE a choice of ADO or DAO. What this means is that when you look at a combo box or list box or form, you'll get off the confused really fast if you start looking for some type of connection string or asking if that combo box is based on ADO or DAO (hint: you as a genera rule don't have a choice in this matter: all of these object and how they work are handled automatically for you internally inside of a MS access). What this means is all you have to do supply the given object with some SQL, and you're done.
So, all of these objects will as a rule work from your linked tables in access. Once these linked tables are set up, then you build forms, or reports, or list box is based on these linked tables. As a result a as mentioned, you'll not be choosing ( or even have to bother) with DAO or ADO when working with these objects.
The choice of ADO or DAO We'll generally only come into play in your actual code that opens a record set or query directly. Most of the code in a form can be based on referencing the controls or objects such as an combo box that exist on that form. Once again the choice of ADO or DAO it not relevant, and you don't have control over that aspect.
For example, if you wanted to use code to setup the values for a combo box, you would use the following code: (we assume the combo box is a two column combo box, 1st column is id (hidden) and 2nd column company name.
The VBA code to fill or setup the combo box via sql is:
Me.Mycombobox.RowSource = "select id, CompnayName from tblCustomers"
That is it!
Notice how there's no connection strings, no record sets, you just shoved some clean SQL right into the combo box row source and away you go.
Now of course the above assumes you have a linked table called "tblCustomers". You can see/view those tables in the tables tab.
( By the way our combo boxes and listbox is allow more than two columns, to hide columns you set the format lengthy equal to zero for that column. That way you can still access the data in your code, but not have that column displayed in the list box).
So the choice of ADO/ADO is often not an issue. Note that even when you do choose ADO or DAO in your code, you as a general rule should use the built in table objects and this again will not have to bother with an connection string built in code. There are some exceptions here, but let's keep this general for the time being.
The above should clear up a lot of your questions about how come you can't see or tell how the form is using DAO or ADO ( the answer is you don't bother with this, and the answers you don't have a choice, and the answer is this is all automatically handled internally for you by MS access)
2.i have stuff in a listbox, how do i use the .GetRows method to put the recordset into a two-dimensional array?
For what reason do you want to do the above? There is VERY little reason to pull data from a listbox into a array. You have the list box ALREADY loaded up with data, so why then waste time loading this data into an array? For what reason would you do this?
You can reference the data in that listbox, but you might want explain what you're trying to accomplish here. There's no need to pull the data out of the listbox, but you can use code in a form to look at value(s) selected in the listbox, and do a useful things with those selections made. Again, to work with the selected data from that listbox, you don't need an array, you don't need connection strings, and you don't need to write a whole bunch of code to repeat what is our data currying and is available inside of that form (hint: the data inside of that list box is available for you as a collection).
So you don't need a record set, you don't need to write a whole bunch of code nor do you need some connection strings. And you don't need nor want to pull that data from that list box into an array, it's simply not required and is completely overkill. Simply stay what you're trying to do with that listbox, and we'll come up with a solution that's likely only a couple of lines of code.
As mentioned, look at that data tab of a listbox, and take a look at the SQL used to fill that listbox. Does that sql run correctly, and furthermore check of the number of columns specified in the listbox matches the number of columns you have in your SQL that set for that list box in the data tab. Funny things can happen if the number of columns don't match the settings for the number of columns in the listbox.