I have a form MFForm that relies on a temp table MFTable. I want to refresh the contents of this table whenever the form opens.
To do this, I'm using the following VBA code in MFForm:
Private Sub Form_Open(Cancel As Integer)
CurrentDb.execute "drop table MFTable", dbFailOnError
CurrentDb.execute "select * into MFTable from MFQuery", dbFailOnError
End Sub
But when I double-click the form to open it, I get the following error on the drop table command:
Run-time error '32111:
The database engine could not lock table 'MFTable'
because it is already in use by another person or process.
I think the problem is that as soon as I click on the form to run it, the temp table goes into use, even before the Form_Open() function executes. How can I make sure that the table's contents are refreshed whenever the form opens?
Here I assume your table's schema is not constantly changing, and clear the table instead of dropping it.
CurrentDb.Execute "delete * from MFTable", dbFailOnError
CurrentDb.Execute "insert into MFTable select * from MFQuery", dbFailOnError
Me.Requery
If your schema is changing constantly then you will need to execute that code before the form is opened. I have not tested this but you may be able to make your form a subform of another form and have that other form drop and recreate the table before the subform opens.
Related
I am trying to refresh 2 queries,
MyTaskQuery and MyTaskActions
Both queries contain an INSERT SLQ statement to insert values from other tables in to table MyTasksTbl
The Query MyTaskQuery then selects the actions from MyTasksTbl that have my username.
When I've added the Delete SQL command (to remove any completed/closed actions and ensure there are no duplicates), I get a
Run-time error 2046, The command or action 'Requery' isn't available
now.
Can anyone advise me why I am getting this error? The code runs on form_load()
SQL = "Delete * From MyTasks Where UserName = '" & User & "';"
DoCmd.RunSQL SQL
DoCmd.Requery MyTaskQuery
DoCmd.OpenQuery MyTasksActions
You can only requery open objects. You can get this error when trying to requery a closed object.
You can test if a query is opened before requerying with the following code:
'Since you aren't using apostrophes, I assume the query name is stored in a variable
If CurrentData.AllQueries(MyTaskQuery).IsLoaded Then
DoCmd.Requery MyTaskQuery
End If
Note that opening an object just to requery it is pointless, since it already requeries when opened.
I am trying to create a temporary table using the CreateTableDef method, and set that table as the record source of a subform in my access database when the parent form loads:
Private Sub Form_Load()
Dim db As Database
Dim tblDef As TableDef
Set db = CurrentDb
Set tblDef = db.CreateTableDef("tblMyTable")
tblDef.Fields.Append tblDef.CreateField("Field1", dbText)
tblDef.Fields.Append tblDef.CreateField("Fields", dbText)
tblDef.Fields.Append tblDef.CreateField("Field3", dbText)
db.TableDefs.Append tblDef
db.TableDefs.refresh
Me.sfrm.Form.RecordSource = "SELECT * FROM tblmyTable"
Me.sfrm.Form.Requery
End Sub
However, when the execution reaches to: Me.sfrm.Form.RecordSource = "SELECT * FROM tblIHC", it raises the run time error 2467: "the expression you entered refers to an object that is closed or does not exist."
Help is appreciated. Also, do I also need to set the source object property of the subform as well? And to what, if so.
It is much easier to simple use currentDB.Execute("CREATE TABLE tblMyTable (Field1 Text, field2 Text, field3 Text);"
But for the record source have you tried adding a ; at the end of the Select?
Do you have two subforms?
Should it read:
Me!IHCResults_subform.Form.RecordSource = "SELECT * FROM tblmyTable"
Me!IHCResults_subform.Form.Requery
And, if so, the last line is not needed. The subform will requery when changing the recordsource.
Also have in mind, that when you open the form, first the subform is opened (hidden), then closed, then the parent form is opened, and this opens the subform. So the subform must initially contain a valid recordsource.
I want to run a saved access query through a button click using VBA. I don't want the user to be asked to confirm that it runs.
CODE:
DoCmd.OpenQuery "QryAddTraining", acViewNormal, acAdd
This brings up the dialogue box "You are about to run append query that will modify data in your table" ....
I just want the VBA code to automatically select "Yes" and stop the user from seeing this interface.
Use DAO.Database.Execute to execute your query:
Dim db As DAO.Database
Set db = CurrentDb
db.Execute "QryAddTraining", dbFailOnError
The dbFailOnError option is not required, but including it gives you better error information. Check the Access help topic for details.
I'm having a bit of trouble with some vba script i'm attempting to run from a button on a form.
Via a linked MDB file, I've written a string of Make Table queries that help certain other queries work. Rather than have the user re-run each individual Make Table query one-by-one, I've put the queries in a VBA script (using DoCmd.RunSQL) and then assigned that script to a button on a form.
The data source i'm using also has a File Info table that contains the File Name and the File Date of the data.
When the user clicks the button, I'd like them to know what data source was used when the string of Make Tables queries was run; that way they know what data the script was run on.
My approach to this was to create a final Make Table query using the File Info table to put the File Name and File Date in it's own table.
I would then add these fields to the form and add the DoCmd.RunSQL for this final Make Table query in to the bottom of the VBA script for the button; once all the Make Tables had run, the File Info and File Date fields would then be displayed/updated on the form telling the user what data file had been used the last time the script was run.
Here's the code for this (for brevity I've summarised all the Make Table scripts that run prior to the FileInfo as some bogus "AllOtherMakeTables" string)
Private Sub Command0_Click()
On Error GoTo Err_Command0_Click
DoCmd.SetWarnings False
Dim AllOtherMakeTables As String
Dim FileInfoStamp As String
AllOtherMakeTables = " SELECT SomeField INTO AnotherTable" _
& " FROM SomeTable" _
FileInfoStamp = " SELECT FileInfo.FileName, FileInfo.FileDate INTO FileInfoStamp" _
& " FROM FileInfo;" _
DoCmd.RunSQL AllOtherMakeTables
DoCmd.RunSQL FileInfoStamp
DoCmd.SetWarnings True
Exit_Command0_Click:
Exit Sub
Err_Command0_Click:
MsgBox Err.Description
Resume Exit_Command0_Click
End Sub
Clicking the button using the script above yields the following error message:
The database engine could not lock table 'FileInfoStamp' because it is
already in use by another person or process
I think what is happening is the fields I added to the form (FileName and FileDate) are locking the FileInfoStamp table when the form is open, so when the script tries to recreate the FileInfoStamp it is unable to do this as the table is locked.
I thought this might be fixed simply by adding a DoCmd.Close at the start of the above script and then adding a DoCmd.OpenForm at the end of the script (essentially closing the form whilst the Make Table commands are run and then re-opening the form at the end).
All this does though is close the form and bring up the same error message. So I guess even though the form is "closed" the connections with the fields on the form still remain active in some way(...?)
Any assistance on how I might get around this would be much appreciated. Thank you.
Do not recreate FileInfoStamp each time. Use these two steps instead:
discard existing rows
append the new data
Dim db As DAO.database
Dim FileInfoStamp As String
FileInfoStamp = "INSERT INTO FileInfoStamp(FileName, FileDate)" & vbCrLf & _
"SELECT fi.FileName, fi.FileDate FROM FileInfo AS fi;"
Debug.Print FileInfoStamp
Set db = CurrentDb
' empty out FileInfoStamp
db.Execute "DELETE FROM FileInfoStamp;", dbFailOnError
' add new data to FileInfoStamp
db.Execute FileInfoStamp, dbFailOnError
Set db = Nothing
Add an error handler to deal with any problems turned up from dbFailOnError.
Instead of DoCmd.RunSQL, use the DAO database .Execute method for your other queries. With that approach, you will not have any motivation to use DoCmd.SetWarnings False. Turning SetWarnings off is unwise because it suppresses information you need to diagnose problems.
I have a subform that is part of a larger form in which both contain a PROJECT_ID field. In the main form, the PROJECT_ID field is a key. In the subform, users have the option of a assigning a new representative to the project or making changes to the current project representatives in the subform. A project can have multiple representatives, however only one can be an active primary. My issue is I’m having trouble writing the validation for the primary flag field (ADV_FLAG) because it’s essentially based on a query. I’m a bit of a novice when it comes to VBA, but I think it’s probably the best solution for my issue. Any suggestions or samples of similar code on how to go about solving this issue. Below is currently what I have in the sub_form’s BeforeUpdate Event Procedure.
Private Sub Form_BeforeUpdate(Cancel As Integer)
'Validation for more than one Active Primary on Project
‘Append to the table T_Error_Catch the project_ID and an error_flag of YES
'where a project has more than one active primary.
DoCmd.SetWarnings False
DoCmd.OpenQuery "Q_Append_Errors_MultiplePrimaries", acViewNormal, acEdit
‘Throw an dialog box error to user to indicate this project already has one active primary
If ERR_FLAG = "Yes" And ADV_FLAG.Value <> "Secondary" Then
MsgBox "Project already has an Active Primary.", vbExclamation
ADV_FLAG.SetFocus
Cancel = True
End If
‘Truncate the T_Error_Catch table once the record has been corrected and there is again only one active primary
If ERR_FLAG = "Yes" And ADV_FLAG.Value = "Secondary" Then
DoCmd.SetWarnings False
DoCmd.OpenQuery "Clear T_Error_Catch", acViewNormal, acEdit
End If
End Sub
You're using form before update to validate ADV_FLAG values in existing records. I think you need to also address new records ... to prevent the user from adding a new representative as primary for a PROJECT_ID which already has a primary representative assigned. You could add a procedure for form before insert to deal with that.
However, rather than waiting until the user has completed all the fields before validating ADV_FLAG, do the validating in the after update event of the ADV_FLAG control. The after update procedure would handle both record update and insert.
But perhaps even easier to implement would be a command button on the subform which makes the current representative the sole primary for the current PROJECT_ID. The button's click event could use code such as this:
Dim strSql As String
Dim db As DAO.Database
On Error GoTo ErrorHandler
strSql = "UPDATE YourTable SET ADV_FLAG = 'Secondary' WHERE PROJECT_ID = " & _
Me.txtPROJECT_ID & ";"
Debug.Print strSql
Set db = CurrentDb
db.Execute strSql, dbFailOnError
Me.txtADV_FLAG = "Primary"
ExitHere:
On Error GoTo 0
Debug.Print "RecordsAffected: " & db.RecordsAffected
Set db = Nothing
Exit Sub
ErrorHandler:
'your error handler code here '
I assumed your subform has a text box control named txtPROJECT_ID which is bound to the PROJECT_ID field, and another named txtADV_FLG bound to the ADV_FLAG field. Change those names as required to match your data controls.
With this approach, there's not really a need for the user to directly edit values in txtADV_FLG (since the command button will make any changes needed). So in the property sheet for txtADV_FLG you can set Enabled = No, and optionally Locked = Yes.
The Debug.Print lines are to help you troubleshoot problems. They will print information to the Immediate Window. (You can go to the Immediate Window with the Ctrl+g keyboard shortcut.) After you have the code running correctly, you could disable or remove the Debug.Print statements. Or leave them as is ... you won't suffer any significant performance hit.
Notice I used db.Execute strSql, dbFailOnError instead of DoCmd.SetWarnings False and DoCmd.OpenQuery. I never SetWarnings off. If you do it, you must remember to SetWarnings back on again afterward. Your code didn't include DoCmd.SetWarnings True. So without SetWarnings on, you risk suppressing important information. Don't do that!
My eyes glazed over trying to follow #HansUp's solution, which I'm sure is correct. I'll instead offer an answer that uses the schema design to obviate any need to write much in the way of code.
I've had to do this many times -- you have a N:1 table but you want one of the records to be designated as PRIMARY.
First, you set up your N:1 table.
Then you add a field to the main table (the 1 side) and have that store the PK value of the record in the N table that you want as your main record.
For instance, say you have tblInventory and tblImage, which has an ImageID PK and an InventoryID FK.
To set one of those as the main image, you'd add a MainImageID field to tblInventory, and edit it with a combo box that lists the images from tblImage that are joined to that InventoryID in tblImage. You'd have to requery the combo box in the Inventory form's OnCurrent event, of course.
An example UI is here:
In that implementation, the list of images has a checkbox for TOP, but it's not editable (and that's a bad UI, since it's not clear from looking that it can't be changed there), but users figure it out fairly quickly. It's certainly not necessary that the check be displayed there, or that the same control be used to indicate the TOP item.