Is there a way to find out what Autofilter has been applied to a query?
I can't use a form, as the database structure is changing (I can't do anything about it). So using a form and Me.Filter is sadly out. Is there anything similar for an opened select query?
What I'm doing now, but it makes me sick:
DoCmd.RunCommand acCmdSelectAllRecords
DoCmd.RunCommand acCmdCopy
I'd actually need to run another query against the filtered query. So: pasting everything into a new table would be OK, getting filter settings as a list of conditions or an SQL statement would be better.
Any ideas?
It seems you know how to examine a form's user-applied filter, but you don't want to use a form because the database schema is still volatile, which means that your query's field set is likely to change.
In that case, create a simple container form with a subform control and use your query as the subform control's SourceObject.
Here is a simple example with a named query (qryFoo2) as SourceObject ...
? Forms!Form20!Child0.SourceObject
Query.qryFoo2
With no user filter applied ...
? Forms!Form20!Child0.Form.Filter
? Forms!Form20!Child0.Form.FilterOn
False
Then if I apply a ("starts with 'h'") filter on my query's text field ...
? Forms!Form20!Child0.Form.Filter
([qryFoo2].[text_field] Like "h*")
? Forms!Form20!Child0.Form.FilterOn
True
Neither have I heard of Autofilter, and I believe Me.Filter returns any applied filter (except in the recordsource, of course) of the form.
However, if you experience that this is not so, you should be able to use the RecordsetClone as it always returns the current records displayed in the form:
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
If rs.RecordCount > 0 Then
While rs.EOF = False
' Loop rs and do stuff.
rs.MoveNext
Wend
End If
Set rs = Nothing
Related
I have an AccessDB app where I need to grab the ItemIDs for the current user-applied filter into a new table to use downstream. Using the subform datasheet .recordsetclone property I can see the desired recordset, .recordcount reports the correct number of records. Otherwise, the following does not produce the desired temp table and AccessVBA does not complain.
Dim db As DAO.Database
Dim rstItemIDs As DAO.Recordset
Dim strSQL as String
Set db = CurrentDb
set rstItemIDs = Forms!Mainform![Data subform].Form.RecordsetClone
msgbox rstItemIDs.recordcount 'reports the correct result
strSQL = "SELECT rstItemIDs.ItemID INTO tempTable FROM rstItemIDs;"
db.Execute strSQL
Is it possible to construct a SQL Select query against a dao.recordset?
Thanks for any pointers you can provide.
Access SQL will not accept either a DAO or ADODB Recordset as the data source for a query.
However, I'm puzzled that Access does not complain when you try. With every attempt I made to reproduce your sample code, I got error #3078, "The Microsoft Access database engine cannot find the input table or query 'rstItemIDs'. Make sure it exists and that its name is spelled correctly."
Even DoCmd.SetWarnings False did not suppress that error message.
If you're interested in alternatives, you could persist tempTable (instead of creating a new version each time), then delete its contents and move through rstItemIDs adding each value to the second recordset. Although that is a RBAR (row by agonizing row) method, it may not be too painful with a small recordset.
A set-based approach could be to create a query based on your form's .RecordSource and .Filter properties. For example, with my form's .RecordSource as SELECT * FROM foo and the current form .Filter as id>10, this would give me a SELECT which returns the form's filtered records:
Replace(Me.RecordSource, ";", "") & vbcrlf & "AND " & Me.Filter
I have a job-tracking system, and there is a query that returns results of all jobs that are overdue.
I have a form that displays each of these jobs one-by-one, and has two buttons (Job has been completed, and Job not completed). Not completed simply shows the next record.
I cannot find a way to get access to the current record to update it's contents if the "Has been Completed" button is pressed, the closest I can get is the long number which represents the records position in the form.
The VBA to get the index of the record in the form is as follows.
Sub Jobcompleted(frm As Form)
Dim curr_rec_num As Long
curr_rec_num = frm.CurrentRecord
End Sub
This is my first shot at VBA, and after an hour of searching I cannot find anything to solve my problem.
Am I going about this the entirely wrong way? Working in Microsoft Access 2007
Further Info All tables are normalized
Vehicle Table: Contains vehicle_id(pk), as well as rego and model etc
Job Table: Contains job_id(pk), vehicle_id(fk) and other info about what needs to happen, as well as the next occurance date, days between each occurance of the job (all jobs repeat) and other info
Job History Table: Contains job_history_id(pk), job_id(fk), date completed and comments
When the job completed button is pressed, it should create a new entry in the job history table with the current date, any comments and the job id
This is the script I am trying to get working
Private Sub Command29_Click()
Dim strSQL1 As String
Dim strSQL2 As String
Set Rs = CurrentRs
Set db = CurrentDb
strSQL1 = "INSERT INTO completed_jobs(JOB_ID, DATE_COMPLETED, COMMENTS) VALUES " & Rs!job.ID & ", " & Date
db.Execute strSQL1, dbFailOnError
strSQL2 = "UPDATE job SET JOB_NEXT_OCCURANCE = JOB_NEXT_OCCURANCE+JOB_RECURRANCE_RATE WHERE job.ID = Rs!job.ID"
db.Execute strSQL2, dbFailOnError
End Sub
Note: Line Set Rs = CurrentRs is completely incorrect, I believe this is what I need to figure out? This is called on button-press
I am posting an image which shows the form (non-continuous).
#HansUp, I get what you are saying, but I dont quite think it's applicable (I did not provide enough information first time around for you to understand I think)
#sarh I believe this Recordset that you are talking about is what I need, however I cannot figure out how to use it, any hints?
#Matt I am 90% sure I am using a bound form (Like I said, new to Access, been looking at everything people have suggested and learning as I go). There is of course an ID for the job (Just not shown, no need to be visible), but how would I access this to perform an operation on it? SQL I can do, integrating with Access/VBA I am new at
As I understand your situation, your form is data-bound bound (you can get record index), so - your form already located on this record. If you need to update some field of underlying dataset, you can write something like
Me!SomeField = ...
DoCmd.RunCommand acCmdSaveRecord
If your form has control bound to "SomeField", then the form will be updated automatically.
If this will not help, you can look to a couple of another directions:
1) Update records using SQL code. For example, you have ID of record that should be updated in the form data set, so you can write something like:
Call CurrentDB.Execute( _
"UPDATE SomeTable SET SomeField = SomeValue WHERE SomeTableID = " & Me!SomeTableID, dbSeeChanges)
2) You can look at the Bookmark property - both Recordset and Form has this property, it describes the record position. So you can write something like this (not the best example, but can help you to get an idea):
Dim Rs as Recordset
Set Rs = Me.RecordsetClone 'make a reference copy of the form recordset
Rs.Bookmark = Me.Bookmark 'locate this recordset to the form current record
Consider a simpler approach. I doubt you need to be concerned with the form's CurrentRecord property. And I don't see why you should need a command button for "Has been Completed" and another for "Has not been Completed".
Add a "Yes/No" data type field to the table which is used by your form's record source. Set it's default value property to 0, which represents False or No. Call it "completion_status". Create a new form using that record source. Then your form can have a check box control for completion_status.
Newly added records will have False/No as completion_status --- the check box will appear unchecked. The completion_status for other records in the forms can be toggled between Yes (checked) and No (unchecked) using the check box control.
I have an Access 2003 form with one subform, set to continuous forms, in a subform control. For one record in the main form, 1 to many records will appear in the sub form. The data displays properly.
The main form is named Widgets and the sub form is named Transactions. There are 5 textbox controls that display the data in the subform. The one in question is ReceiptDate.
What I would like to do is look at the values and determine if there was a receipt for the year 2009, and if so then change the background of that row to yellow so it stands out when the user encounters that condition. Maybe even change the date field's font to boldface..
I tried many ways of referencing the subform's controls. When I have tried Me.Transactions.ReceiptDate I have only received the first record in that subform. I'd like to be able to loop through them and see if the condition is met. I tried Me.Transactions.ReceiptDate(1) and Me.Transactions.ReceiptDate(0) and so forth.
I tried the For Each ctl In Form.Controls route as well. It worked for a few iterations and then I received a run-time error 2455 "You entered an expression that has an invalid reference to the property Form/Report".
I had the subform in "datasheet" mode but thought that was causing me not to be able to read through an array of subform controls. So I changed it to "continuous" mode. I get the same errors for either.
Is there a way to reference specific "rows" in the subform and do something based on a value found? Also, I am performing this in the On Current event as I dont know where else to put the code. The subform loads before the parent form so its possible that these controls arent even fully "there" but then I do get the first row's date when I try it in the Immediate Window.
UPDATE 12.23.2010:
With the gracious help of #Remou I am able to debug.print the ReceiptDate fields from the RecordSet. This is great because now I can evaluate the data and do certain things based on the values.. The #Remou's code helped me put this into the OnCurrent event:
Dim i As Long
Dim frm As Form
Dim rs As DAO.Recordset
' Get the form and its recordset.
Set frm = Me.Form
Set rs = frm.RecordsetClone
' Move to the first record in the recordset.
rs.MoveFirst
' Move to the first selected record.
rs.Move frm.SelTop - 1
' Enumerate the list of selected records presenting the ReceiptDate field
For i = 1 To rs.RecordCount
Debug.Print rs![ReceiptDate]
rs.MoveNext
Next i
So now that I am able to know which row in my subform has a receipt from 2009, I need to be able to highlight the entire row or rows as I come across them in that for loop. How can I reference the actual row? Datasheet view or Continuous Forms view - I have tried both.
Conditional Formatting is great but it only allows me to highlight one particular record and I'd much rather be able to do this via VBA because...... from here I will want to give the use the ability to click on any record in the subform and get the receipt details and potentially print them.
Any ideas?
In this situation, it is best to use conditional formatting.
To refer to a control on a subform, refer to the subform control by name, then the form property to get the form contained, then the control by name:
Me.MySubformControlName.Form.MyControl
See: http://www.mvps.org/access/forms/frm0031.htm
I have finally got it. The frm.SelTop = x will set the selected record and from there I can set the background or font style, etc.. Very cool. A simple test for 2009 and setting the selected record:
Dim i As Long
Dim frm As Form
Dim rs As DAO.Recordset
' Get the form and its recordset.
Set frm = Me.Form
Set rs = frm.RecordsetClone
' Move to the first record in the recordset.
rs.MoveFirst
' Move to the first selected record.
rs.Move 0
' Enumerate the list of selected records presenting
' the CompanyName field in a message box.
For i = 1 To rs.RecordCount
If Year(rs![ReceiptDate]) = 2009 Then
frm.SelTop = i '<-----------------------------
End If
rs.MoveNext
Next i
In order for me to get the email off the bottom of my continuous form, I used this much simpler code (as I avoided the RecordsetClone code)
Me.[email subform].Form.SelTop = Me.[email subform].Form.Count 'selects the last row
str = Me.[email subform].Form.Email 'capture the value of the last row
MsgBox str
In a continuous subform, I display records based on a DISTINCT query. Because it's distinct, each row does not include a record ID.
Does anyone know of a way to add a checkbox (or similar), so that a user can select any of the records, which will then be used to create new records via code?
I prefer to use a subform to a list, as it features lots of column sorting and filtering functions.
MTIA
Depending on what you need to create the records, something like this sample may suit:
Function DisplaySelectedCompanyNames()
Dim i As Long
Dim F As Form
Dim RS As Recordset
'' Get the form and its recordset.
Set F = Forms![Customers1]
Set RS = F.RecordsetClone
'' Move to the first record in the recordset.
RS.MoveFirst
'' Move to the first selected record.
RS.Move F.SelTop - 1
'' Enumerate the list of selected records presenting
'' the CompanyName field in a message box.
For i = 1 To F.SelHeight
MsgBox RS![CompanyName]
RS.MoveNext
Next i
End Function
Further information: http://support.microsoft.com/kb/208502
FYI, I decided to use the Windows ListView OCX control, as it offers the ability to add a checkbox for each row.
There is some literature available at expert's exchange and at teck republic about using the combobox.recordset property to populate a combobox in an Access form.
These controls are usually populated with a "SELECT *" string in the 'rowsource' properties of the control, referencing a table or query available on the client's side of the app. When I need to display server's side data in a combobox, I create a temporary local table and import requested records. This is time consuming, specially with large tables.
Being able to use a recordset to populate a combobox control would allow the user to directly display data from the server's side.
Inspired by the 2 previous examples, I wrote some code as follow:
Dim rsPersonne as ADODB.recordset
Set rsPersonne = New ADODB.Recordset
Set rsPersonne.ActiveConnection = connexionActive
rsPersonne.CursorType = adOpenDynamic
rsPersonne.LockType = adLockPessimistic
rsPersonne.CursorLocation = adUseClient
rsPersonne.Open "SELECT id_Personne, nomPersonne FROM Tbl_Personne"
fc().Controls("id_Personne").Recordset = rsPersonne
Where:
connexionActive: is my permanent ADO connection to my database server
fc(): is my current/active form
controls("id_Personne"): is the
combobox control to populate with
company's staff list
Access version in 2003
Unfortunately, it doesn't work!
In debug mode, I am able to check that the recordset is properly created, with requested columns and data, and properly associated to the combobox control. Unfortunately, when I display the form, I keep getting an empty combobox, with no records in it! Any help is highly appreciated.
EDIT:
This recordset property is indeed available for the specific combobox object, not for the standard control object, and I was very surprised to discover it a few days ago.
I have already tried to use combobox's callback function, or to populate a list with the "addItem" method of the combobox,. All of these are time consuming.
To set a control that accepts a rowsource to a recordset you do the following:
Set recordset = currentDb.OpenRecordset("SELECT * FROM TABLE", dbOpenSnapshot)
Set control.recordset = recordset
Works with DAO Recordsets for sure, I haven't tried ADO recordsets because I don't have any real reason to use them.
When done this way, a simple requery will not work to refresh the data, you must do a repeat of the set statement.
As was said, you have to get the RowSourceType to "Table/Query" (or "Table/RequĂȘte" if in french) in order to show query results in the combobox.
Your memory problems arise from opening the recordset (rsPersonne) without closing it. You should close them when closing/unloading the form (but then again you would have scope problems since the recordset is declared in the function and not in the form).
You could also try to create and save a query with Access's built-in query creator and plug that same query in the RowSource of your combobox. That way the query is validated and compiled within Access.
I found the trick ... the "rowSourceType" property of the combobox control has to be set to "Table/Query". Display is now ok, but I have now another issue with memory. Since I use these ADO recordsets on my forms, memory usage of Access is increasing each time I browse a form. Memory is not freed either by stopping the browsing or closing the form, making MS Access unstable and regularly freezing. I will open a question if I cannot solve this issue
good method with using the Recordset property, thanks for that hint!
Patrick, the method you shown on your page has a big disadvantage (I tried that too on my own): The value list can only be 32 KB, if you exceed this limit the function will throw an error.
The callback method has the big disadvantage that it is very slow and it is called once for every entry which makes it unuseable for a longer list.
Using the recordset method works very well. I needed this because my SQL string was longer than 32 KB (lot of index values for WHERE ID IN(x,x,x,x,x...)).
Here's a simple function which uses this idea to set a recordset to the combobox:
' Fills a combobox with the result of a recordset.
'
' Works with any length of recordset results (up to 10000 in ADP)
' Useful if strSQL is longer than 32767 characters
'
' Author: Christian Coppes
' Date: 16.09.2009
'
Public Sub fnADOComboboxSetRS(cmb As ComboBox, strSQL As String)
Dim rs As ADODB.Recordset
Dim lngCount As Long
On Error GoTo fnADOComboboxSetRS_Error
Set rs = fnADOSelectCommon(strSQL, adLockReadOnly, adOpenForwardOnly)
If Not rs Is Nothing Then
If Not (rs.EOF And rs.BOF) Then
Set cmb.Recordset = rs
' enforces the combobox to load completely
lngCount = cmb.ListCount
End If
End If
fnADOComboboxSetRS_Exit:
If Not rs Is Nothing Then
If rs.State = adStateOpen Then rs.Close
Set rs = Nothing
End If
Exit Sub
fnADOComboboxSetRS_Error:
Select Case Err
Case Else
fnErr "modODBC->fnADOComboboxSetRS", True
Resume fnADOComboboxSetRS_Exit
End Select
End Sub
(The function fnADOSelectCommon opens an ADO recordset and gives it back. The function fnErr shows a message box with the error, if there was one.)
As this function closes the opened recordset there should be no problem with the memory. I tested it and didn't saw any increasing of memory which wasn't released after closing the form with the comboboxes.
In the Unload Event of the form you can additionaly use a "Set rs=Me.Comboboxname.Recordset" and then close it. This should not be necessary regarding memory, but it may be better to free up open connections (if used with a backend database server).
Cheers,
Christian
A combo box control does not have a recordset property. It does have a RowSource property but Access is expecting a SQL string in there.
You can change the RowSourceType to the name of a user defined "callback" function. Access help will give you more information including sample code by positioning yourself on the RowSourceType and pressing F1. I use this type of function when I want to give the users a list of available reports, drive letters, or other data that is not available via a SQL query.
I don't understand what you mean by your third paragraph with respect to using data directly from the server side. Or rather I don't understand what the problem is with using standard queries.
In MS Access, it's ok, but in VB, you may use something like this using adodc (Jet 4.0):
Private sub Form1_Load()
with Adodc1
.commandtype = adcmdtext
.recordsource = "Select * from courses"
.refresh
while not .recordset.eof
combo1.additem = .recordset.coursecode
.recordset.movenext
wend
end with
End Sub