I created a form that imports a csv file as a new table called "ImportTable". I have queries to look at the data.
Once finished with the data I want to delete the table entirely (as part of the client workflow requirements). I'm stuck on how to apply a delete_table function to an on click event.
I put together the below function to delete the table. How can I apply this to an on click event?
The button name is: cmdDeleteImportTable_Click()
Public Function table_exists(tblName As String) As Boolean
'Returns True if table exists in current DB. Else False
Dim tdf As TableDef
For Each tdf In CurrentDb.TableDefs
If StrComp(tblName, tdf.Name) = 0 Then
table_exists = True
Exit For
End If
Next tdf
End Function
Public Function delete_table(tblName As String) As Boolean
'Returns true if the table is deleted or if the table does not exist
On Error GoTo errHandler
If table_exists(tblName) Then
DoCmd.DeleteObject acTable, tblName
End If
delete_table = True
ExitSuccess:
Exit Function
errHandler:
Debug.Print Err.Number, Err.Description
Resume ExitSuccess
End Function
Sub Test()
Const Names_Table = "ImportTable"
DoCmd.SetWarnings False
Debug.Print delete_table(Names_Table)
DoCmd.SetWarnings True
End Sub
Your code seems correct.
All you need to do now is add it a button. In Access Forms you have to select the button, then in Events tab, you have On Click. Select it and choose code.
This will create an event handler for the click event. Inside this event handler, you can call your code to import data or delete your table.
Further detais Here
Related
I am creating a set of Access database form for entering vegetation data into a linked SQL Server data base. For one protocol, I have created a form 'frmLPI' for entering data from a vegetation monitoring method called Line-Point-Intercept. It is a form with a subform within it called 'frmLPIDetail' where individual counts of plant species get recorded. The main form has three unbound controls: [TransectOID], [DataRec], and [DataObs]. TransectOID is a unique id for each time we ran protocol. For each TransectOID, there are 30 locations where we sampled vegetation these have a hidden unique id in the subform called LPI_OID. The subform is linked to the main form by TransectOID. I want my users to be able to click the unbound [DataRec] and [DataObs] comboboxes in the main form, and have the corresponding fields in the subform autopopulate for all 30 records. I have figure out how to accomplish this for record in the subform but can't figure out how to do it for 30 records for each value of TransectOID in the Main form. Below is a screenshot of my form to help you visualize what I am after:
And here is the code I have come up with to get one record to autopopulate
Private Sub Form_Load()
Me.TransectOID = Me.OpenArgs
End Sub
Private Sub Form_Deactivate()
DoCmd.RunCommand acCmdSaveRecord
End Sub
Private Sub DataObs_AfterUpdate()
Me!frmLPIDetail.Form!Data_observer = Me!DataObs
Me.Dirty = False
End Sub
Private Sub DataRec_AfterUpdate()
Me!frmLPIDetail.Form!Data_recorder = Me!DataRec
Me.Dirty = False
End Sub
Any suggestions would be much appreciated
Since inserting multiple records at a time is desirable your question has been asked before but I couldn't find an answer that was particularly helpful so I will provide a more general answer than you asked for.
Access doesn't provide default forms for inserting multiple records. You have to code that yourself but the process is always pretty much the same.
figure out a normalized table structure for your data
figure what data you need to collect from the user for the multiple insert
add a button to the form and put the vba for the multiple insert in the click event
so here is 1 normalized table structure that might fit your data:
Since I don't know where TransectionOID is coming from we let Access provide TransectionID as the primary key and assume TransectionOID is entered on another form. All the other information of interest is in the TransectionDetails table and there is no need to write a query to gather all the variables we will need into our forms record source to finish step 2. To get a jumpstart I selected the TransactionDetails table and used the create form wizard to make a tabular style form.
To finish step 2 we put controls in the header to collect the information from the user we will need and the start editing the form for user friendliness. For instance I delete the checkbox for TransectionDetailID in the details section and replace every other control with comboboxes. I normally replace the circled record selectors with comboboxes as well but here that may be confusing so I leave the record selectors to provide some search functionality. The final form looks like:
Finally, for step 3 we add the vba for the click event
Private Sub cmdInsert_Click()
Dim db As Database
Dim rs As Recordset 'using recordset because lower error rate than using sql strings
Set db = CurrentDb
Set rs = db.OpenRecordset("TransectionDetails")
Dim L As Integer
Dim S As Integer
If Not Me.lstLocations.ListCount = 0 Then 'if no locations are selected no records can be inserted
For L = 0 To Me.lstLocations.ListCount 'simple multiselect listbox version matters for the vba code
If Me.lstLocations.Selected(L) = True Then
For S = 0 To Me.lstSpecies.ListCount
If Me.lstSpecies.Selected(S) = True Then
rs.AddNew
rs!TransectionID = Me.cmbTransectionID
rs!Data_observer = Me.cmbData_observer
rs!Data_recorder = Me.cmbData_recorder
rs!TransectLocation = Me.lstLocations.Column(0, L) 'column gives you access to values in the listbox
rs!SpeciesID = Me.lstSpecies.Column(0, S)
If Not IsNull(Me.chkDead) Then 'chkDead is a triple value checkbox, this both avoids setting Dead to null and shows how to handle when the user doesn't set all controls
rs!Dead = Me.chkDead
End If 'chkdead
rs.Update
End If 'lstspecies selected
Next S
End If
Next L
End If
Me.Detail.Visible = True 'quick and dirty bit of style (detail starts invisible)
Me.Filter = "TransectionID = " & Me.cmbTransectionID 'more quick and dirty style filter to focus on inserted records
Me.FilterOn = True
'clean up
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
Private Sub cmdSelectAllLocations_Click()
Dim i As Integer
For i = 0 To Me.lstLocations.ListCount
Me.lstLocations.Selected(i) = True
Next
End Sub
Private Sub cmdSelectAllSpecies_Click()
Dim i As Integer
For i = 0 To Me.lstSpecies.ListCount
Me.lstSpecies.Selected(i) = True
Next
End Sub
Private Sub cmdSelectNoLocations_Click()
Dim i As Integer
For i = 0 To Me.lstLocations.ListCount
Me.lstLocations.Selected(i) = False
Next
End Sub
Private Sub cmdSelectNoSpecies_Click()
Dim i As Integer
For i = 0 To Me.lstSpecies.ListCount
Me.lstSpecies.Selected(i) = False
Next
End Sub
While Mazoula's answer is far more elegant, I discovered a quick and dirty way to accomplish what I was after using a While loop. Below is my code:
Private Sub Form_Load()
Me.TransectOID = Me.OpenArgs
End Sub
Private Sub Form_Deactivate()
DoCmd.RunCommand acCmdSaveRecord
End Sub
Private Sub DataObs_AfterUpdate()
Dim rs As DAO.Recordset
Set rs = Me!frmLPIDetail.Form.RecordsetClone
rs.MoveLast
rs.MoveFirst
While Not rs.EOF
rs.Edit
rs!Data_observer.Value = Me.DataObs.Value
rs.Update
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
Me.Dirty = False
End Sub
Private Sub DataRec_AfterUpdate()
Dim rs As DAO.Recordset
Set rs = Me!frmLPIDetail.Form.RecordsetClone
rs.MoveLast
rs.MoveFirst
While Not rs.EOF
rs.Edit
rs!Data_recorder.Value = Me.DataRec.Value
rs.Update
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
Me.Dirty = False
End Sub
For various reasons, I want to set up a custom button on my forms to save the current record. I use a navigation form and want to trigger the same process (integrity-checks, user input etc.) whenever the entry is saved, thus whenever the user presses the "save"-button or switches to another form. The user will conditionally be asked to confirm the process and is thus able to cancel it as well.
Everything is running smoothly with one really odd and annoying exception: Whenever I click the save button on a new record and prompt a message within the "BeforeUpdate" event, I receive
RTE 3021 ("no current record")
Without the MsgBox, everything is fine. Even more strange:
When I trigger the save process by switching to another form using the navigation form (or simply press "outside" the form used for data entry), everything is fine as well.
Here is a minimalistic example (similar results with DoCmd.Save, Requery or acCmdSaveRecord):
Private Sub vt_save_Click()
Me.Dirty = False
End Sub
Private Form_BeforeUpdate(Cancel As Integer)
Cancel = True
MsgBox "Test"
End Sub
Any ideas? I simply can't wrap my head around that error.
You could maybe try to run a query using the values in the form while checking if the record exists or not.
Is there a primary key on the table? if so, the primary key will be your focal point.
Private Sub vt_Save_Click()
dim rst as DAO>Recordset
Dim strSQL as String
Dim strID as string
strID = me.YourPrimaryKeyField
strSQL = "SELECT * " & _
"FROM YourTableName " & _
"WHERE (((YourTableName.YourFieldName) =" & me.PrimaryKeyField & "));"
set rst = currentdb.openrecordset(strsql)
if rst.recordcount = 0 then
currentdb.execute "INSERT INTO YourTableName ( List All Fields to Add ) " & _
"SELECT List All Field controls with values to add;"
End IF
'Anything else you want the code to do from here
EndCode:
If not rst is nothing then
rst.close
set rst = nothing
End IF
End Sub
Repeat this process for the Form_LostFocus() event. If you want to make it easier, make this code a module and call within both event triggers on your form.
If this doesn't work please let me know and I will be happy to further assist.
The most straight forward and reasonable solution is to use an Error Handler - which I ignored so far tenaciously.
Private Sub save_Click()
On Error GoTo Err_Handler
Me.Dirty = False
Exit_Here:
Exit Sub
Err_Handler:
If Err.Number = 2101 Then
'ignore or message
Else
MsgBox Err.Description
End If
Resume Exit_Here
End Sub
I'm trying to create a finance database that requires users to sign in and log out. I have that part working correctly. On the homepage of the database, I'm trying to get their last 25 (or X number) of transactions to display using a query. For some reason, I cannot get the code to pass as it shows a "Data type mismatch." Here is the various code - I'll explain each as I go:
Global Variables (My Global Module)
Option Compare Database
'global variables
Global C As Long
Global C2 As Long
Global HoldString As String
Global Flag As Boolean
Global Reply As String
Global mbReply As VbMsgBoxResult
Global User As String
Global GUser As Long
Global db As Database
The following are the Subs() to Log In (First Sub() is for Exit button, second sub() is for sign in button):
Option Compare Database
Private Sub B_Exit_Click()
mbReply = MsgBox(title:="Exit", _
prompt:="Are you sure you wish to exit the system?", _
Buttons:=vbYesNo)
If mbReply = vbNo Then
Exit Sub
Else
DoCmd.Quit acQuitSaveNone
End If
End Sub
Private Sub B_SignIn_Click()
'variables
Set db = CurrentDb()
Dim Employees As DAO.Recordset
Set Employees = db.OpenRecordset("Employees", dbOpenDynaset)
Dim isEmployeed As Boolean
Dim PassMatch As Boolean
Dim isTerm As Boolean
'check to see if the user is in the system
isEmployeed = False
PassMatch = False
isTerm = False
Do While Not Employees.EOF
If Employees![UserName] = T_Username.Value Then
isEmployeed = True
'make sure the employee is not terminated
If Employees![Terminated] = "Yes" Then
isTerm = True
End If
If isTerm = True Then
MsgBox ("This user has been terminated.")
Exit Sub
End If
'make sure password is correct
If Employees![Password] = T_Password.Value Then
PassMatch = True
End If
If PassMatch = False Then
MsgBox ("Incorrect Password.")
Exit Sub
End If
'mark signed in
Employees.Edit
Employees![SignedIn] = 1
Employees.Update
User = Employees![FirstName] & " " & Employees![LastName]
GUser = Employees![ID] 'Sets GUswer to equal record ID.
End If
Employees.MoveNext
Loop
If isEmployeed = False Then
MsgBox ("This username is not in the system.")
Exit Sub
End If
'close this form and open the main menu
Employees.Close
DoCmd.OpenForm FormName:="HomePage"
DoCmd.Close acForm, Me.Name, acSaveNo
End Sub
The next is my SQL code for the query:
SELECT TOP 25 Spend.ID, Spend.Vendor, Spend.MaterialGroup, Spend.GLCode, Spend.CostCenter, Spend.Department, Spend.InvoiceNumber, Spend.InvoiceDate, Spend.Amount, Spend.Tax, Spend.Total, Spend.DateEntered, Spend.DocNumber, Spend.Description, Spend.[Paid?], Spend.EnteredBy, Spend.EnteredBy
FROM Spend
WHERE (((Spend.[EnteredBy])="GUser"));
Spend.[EnteredBy] has a relationship with the Employees table. So EnteredBy is actually a number field because of this relationship.
If I hardcode the "WHERE" statement to be something like (((Spend.[EnteredBy])=2)); then the query will work fine.
Ultimately, what I want to happen is for the query to show the last 25 data entries that the logged on user completed.
Hope this makes sense. If there are questions, please let me know. I feel like I'm missing something small but I cannot figure it out.
Thanks,
Clark
Your query should read:
SELECT TOP 25 Spend.ID, Spend.Vendor, Spend.MaterialGroup, Spend.GLCode, Spend.CostCenter,
Spend.Department, Spend.InvoiceNumber, Spend.InvoiceDate, Spend.Amount, Spend.Tax, Spend.Total,
Spend.DateEntered, Spend.DocNumber, Spend.Description, Spend.[Paid?], Spend.EnteredBy, Spend.EnteredBy
FROM Spend WHERE (((Spend.[EnteredBy])=" & GUser & "));
Note the Ampersands ( & ) I placed before and after your GUser variable. This tells Access to evalute that expression and return the VALUE of it.
I'd also caution you against use the name "User" as a variable name. It's a Reserved Word in Access:
http://office.microsoft.com/en-us/access-help/access-2007-reserved-words-and-symbols-HA010030643.aspx
First of all, you start with a form named LoginF. Once you choose your login ID, and password; and log in it takes data from the table LoginIntoT for the login ID you chose, and creates a query with said data using this code:
On Error Resume Next
DoCmd.DeleteObject acQuery, "IsAdminQ"
On Error GoTo Err_LoginBtn_Click
Dim qdef As DAO.QueryDef
Set qdef = CurrentDb.CreateQueryDef("IsAdminQ", _
"SELECT IsAdmin " & _
"FROM LoginInfoT " & _
"WHERE EmployeeID = " & LoginCmBx.Value)
Exit_LoginBtn_Click:
DoCmd.Close acForm, "LoginF", acSaveNo
DoCmd.OpenForm "MenuF"
Exit Sub
Err_LoginBtn_Click:
MsgBox Err.Description
Resume Exit_LoginBtn_Click
From there in that query after you log in is only 1 column and 1 row; meaning one piece of data. This data is a yes/no field which is either Yes or No depending on who you logged in as.
On the form it opens after you click the login button it has a logout button. The logout button brings you to the previous login form, and deletes the query (IsAdminQ).
What I am trying to do is attach a yes/no button on a form to take that data, and output if it's yes or no on the query.
I've tried putting this in it's control source:
=[IsAdminQ].[IsAdmin]
Though what that does is output it as a filled in square instead of a checkmark or empty. I have triple state set as no.
How would I attach the checkbox to the query so if the data says yes, then it's a check mark and if it says no it is an empty box?
I understand you.
"On the form it opens after you click the login button it has a logout button", we call it frmLogout. You shall do this:
Solution I:
frmLogout.RecordSource = "IsAdminQ"
Then for your checkbox named MyCheckbox, we set it this:
Me.MyCheckbox.ControlSource = "IsAdmin"
You cannot use this:
Me.MyCheckbox.ControlSource = "[IsAdminQ].[IsAdmin]" ' <= here it's impossible.
Solution II:
On the form frmLogout without setting IsAdminQ as .RecordSource,
In a Public Module, insert this:
Function GetLoginStateIsAdmin()
'
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordSet("IsAdminQ")
GetLoginStateIsAdmin = Nz(rst(0), False)
Set rst = Nothing
'
End Function
Then in the private module of any form, as frmLogout:
Private Sub Form_Open(Cancel As Integer)
'
Me.MyCheckbox.Value = GetLoginStateIsAdmin()
'
End Sub
Set it in addition in design mode:
Me.MyCheckbox.TripleState = false
And check also if the query IsAdminQ has been successfully created in the login step. And open it in Access Navigation Pane by double-clicking on it. And see the value of the query.
I am sending data from frmSearchEmployeeWorksheets to frmStatsCorr which runs a query (qryStatsCorr). On frmStatsCorr I am checking to make sure the query returns records otherwise I will Msg the user and return to the search form. My problem is that I am having problems 'ignoring' the 2501 caused by the DoCmd.OpenForm ("frmStatsCorr") which I learned here on Stackoverflow...
What am I doing wrong that is causing me major Access VBA Frustration??
This is the sub on the Search form (frmSearchEmployeeWorksheets):
Private Sub btnSearch_Click()
' I only change focus to force the updated data to submit to query
Me.[txtEmployee].SetFocus
Me.txtShift.SetFocus
If txtUnit = "7" Then
'First close the form in order to update
DoCmd.Close acForm, "frmStatsCorr"
' Open Stats form
On Error GoTo myErr
**DoCmd.OpenForm ("frmStatsCorr") 'causes error**
End If
myExit:
Exit Sub
myErr:
Echo True
If Err.Number = 2501 Then GoTo myExit
MsgBox Err.Description
GoTo myExit
End Sub
In frmStatsCorr I simply check to make sure the query returns records if not I inform the user, close the form, and return to the frmSearchEmployeeWorksheets
Private Sub Form_Load()
If strFormStatus = "view" Then
If DCount("*", "qryStatsCorr") = 0 Then
MsgBox "Your search does not produce any results. Try a different search.", vbOKOnly
DoCmd.Close
DoCmd.OpenForm ("frmSearchEmployeeWorksheets")
Exit Sub
End If
txtDay = WeekdayName(Weekday(Me.WorkDate)) 'This line returns an error so I check for an empty query and return to the search form.
Me.[WorkDate].SetFocus
Me.txtUnit.Enabled = False...
I'm unsure how well I understand your code or the logic behind it. My hunch is you should check the DCount result from btnSearch_Click, and not fiddle with closing then re-opening frmStatsCorr, and having frmStatsCorr close itself when it contains no data. Just do not open frmStatsCorr when it will not contain data.
If the current form (frmSearchEmployeeWorksheets) which holds your btnSearch_Click procedure contains unsaved data changes, you can save them with Me.Dirty = False
Private Sub btnSearch_Click()
Dim strPrompt As String
If Me.Dirty Then ' unsaved data changes
Me.Dirty = False ' save them
End If
If Me.txtUnit = "7" Then
If DCount("*", "qryStatsCorr") = 0 Then
strPrompt = "Your search does not produce any results. " & _
"Try a different search."
MsgBox strPrompt, vbOKOnly
Else
' if frmStatsCorr is open, just Requery
' else open frmStatsCorr
If CurrentProject.AllForms("frmStatsCorr").IsLoaded Then
Forms("frmStatsCorr").Requery
Else
DoCmd.OpenForm "frmStatsCorr"
End If
' uncomment next line to close current form
'DoCmd.Close acForm, Me.Name
End If
End If
End Sub
If frmStatsCorr is open and you need to check whether it is in Design View, examine its CurrentView property.
Forms("frmStatsCorr").CurrentView ' Design View = 0
I suggested that approach because I suspected frmStatsCorr's Form_Load may trigger the 2501 error when it closes itself. But I'm not certain that's the cause of the error and I'm not motivated enough to set up a test.
If you still have 2501 errors with the approach I suggested, there are two other possible causes I've encountered:
corruption
broken references