Deleting Record in MS Access Form With Button - ms-access

Recently started learning Access and I'm a bit stuck on deleting records within a form. I have a list with the following code:
Private Sub lstPickList_AfterUpdate()
Dim rst As DAO.Recordset
Set rst = Me.RecordsetClone
rst.FindFirst "OrderID=" & lstPickList.Column(0) & ""
If rst.NoMatch Then
MsgBox "The selected record can not be displayed." _
& "To display this record, you must first turn off record filtering.", _
vbInformation
Else
Me.Bookmark = rst.Bookmark
End If
Set rst = Nothing
End Sub
And a button that I would like to use to delete whatever Order is currently selected on the list. The "DeleteRecord" macro just gives me a "The command or action 'DeleteRecord' isn't available now." error. Searching has given me a bunch of code that hasn't worked for me at all.

You can delete directly from the clone:
If rst.NoMatch Then
MsgBox "The selected record can not be displayed." _
& "To display this record, you must first turn off record filtering.", _
vbInformation
Else
rst.Delete
End If

Related

MS Access Recordset Moving on Search even if no match found?

This is driving me nuts. I have an access VBA form where I want to allow users to type a document number into a box in order to jump directly to that record.
The underlying table as a field "DocNum", and the number is always sequential. I want the searchbox to display the current Doc Number the user is on, if they type in a different number and hit enter, it should either jump to that record if it exists, or if it doesn't exist, stay on the current record.
I'm trying to accomplish thisby having a hidden textbox bound to "DocNum", and an unbound visible box on top of it. On Form_Current() the unbound box is made to match the underlying field. After, update I run the following code to perform the search.
Private Sub txt_DocNumSearch_AfterUpdate()
Dim rs As Object
Set rs = Me.RecordsetClone
With rs
rs.FindFirst "[DocNum] = " & Str(Me![txt_DocNumSearch])
If rs.NoMatch Then
MsgBox "Record not found."
GoTo Cleanup
Else
Me.Bookmark = rs.Bookmark
Exit Sub
End If
End With
Cleanup:
rs.Close
Set rs = Nothing
Set dbs = Nothing
End Sub
What's driving me insane is that even when it doesn't find a match.... it skips to the next record anyway. No matter what I do... move last, trying to bookmark before I even search, etc... I can't get it to not jump forward. What am I missing?
Try simplifying it:
Private Sub txt_DocNumSearch_AfterUpdate()
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
With rs
.FindFirst "[DocNum] = " & Str(Me![txt_DocNumSearch])
If .NoMatch Then
MsgBox "Record not found."
Else
Me.Bookmark = .Bookmark
End If
.Close
End With
End Sub

How to programmatically select rows in vb6 Datagrid

I have a VB6 Project I am creating and i have a method that searches and edits students from an access database. i need to code the program so it can select the student that was searched and modify it. I saw this webpage but it does not select the student, the user has to select it before making edits, https://support.microsoft.com/en-us/kb/195472 . How do i program it so it can select that particular row so the user can edit.
Code using the website:
Option Explicit
Dim connSearch As New ADODB.Connection
Dim rec As New ADODB.Recordset
Private Sub cmdSearch_Click()
connSearch.Close
connSearch.Open connstr
rec.CursorLocation = adUseClient
If cmbSearch.Text = "Last Name" Then
rec.Open "Select * From Table1 where [Last Name] like '" & txtSearch.Text & "'", connSearch, adOpenDynamic, adLockOptimistic
frmStudents.cmdShowall.Enabled = True
If rec.EOF Then
MsgBox "No Student Found.", vbInformation, "Error"
Else
Set frmStudents.StudentTable.DataSource = rec
MsgBox "Student found Successfully", vbInformation, "Success"
' Remove previously saved bookmark from collection
If (frmStudents.StudentTable.SelBookmarks.Count <> 0) Then
frmStudents.StudentTable.SelBookmarks.Remove 0
End If
' Append your bookmark to the collection of selected rows
frmStudents.StudentTable.SelBookmarks.Add rec.Bookmark
frmSearch.Hide
End If
End If
End Sub
Thanks for the help. :)
EDIT: Move code from comments to here
Private Sub Form_Load()
connSearch.Open connstr 'open the connection
frmStudents.Adodc1.ConnectionString = conn.connstr
Set frmStudents.StudentTable.DataSource = frmStudents.Adodc1
End Sub
You must be using a recordset to fill the frmStudents.Adodc1 Datasource but for some reason you don't want to show that code.
Then in the code you try you're opening a new recordset to search for the student and assign a bookmark. That will not work.
If you want to show all the students - like the example shows - you need to leave the data source alone and do the find on the same recordset used by your datagrid.
It's hard for me to guess what that is since you're not showing me the Form's code - I assume the recordset is global withing the form's module - but maybe not?
Without that information I can guess at something, hoping maybe the translation will work.
Replace this
rec.Open "Select * From Table1 where [Last Name] like '" & txtSearch.Text & "'", connSearch, adOpenDynamic, adLockOptimistic
frmStudents.cmdShowall.Enabled = True
If rec.EOF Then
MsgBox "No Student Found.", vbInformation, "Error"
Else
Set frmStudents.StudentTable.DataSource = rec
MsgBox "Student found Successfully", vbInformation, "Success"
' Remove previously saved bookmark from collection
If (frmStudents.StudentTable.SelBookmarks.Count <> 0) Then
frmStudents.StudentTable.SelBookmarks.Remove 0
End If
' Append your bookmark to the collection of selected rows
frmStudents.StudentTable.SelBookmarks.Add rec.Bookmark
frmSearch.Hide
With this
Dim varBookmark as Variant
With frmStudents.StudentTable
varBookMark = .Bookmark
' Remove previously saved bookmark from collection
If (.SelBookmarks.Count <> 0) Then
.SelBookmarks.Remove 0
End If
.Recordset.Find "[Last Name] like '" & txtSearch.Text & "'"
' If Find method fails, notify user
' If the search fails, the Recordset will point to either EOF or BOF.
If .Recordset.EOF or .Recordset.BOF Then
Msgbox "No Student Found"
' Reset back to last selection
.Recordset.Bookmark = varBookmark
Else
Msgbox "Student Found"
.SelBookmarks.Add .Recordset.Bookmark
Endif
End With
Ideally you'd just use the recordset variable that you assigned to frmStudents.Adodc1 instead of frmStudents.Adodc1.Recordset, but you haven't shared that with me so maybe this will work for you

Microsoft Access - Saving New Record to Linked Database

I am creating a user interface based off of one internal and two linked (external) Access datasheets in Access 2013.
Two of the fields on my UI are combo boxes that read from the linked datasheets and display the options. This is so that the entries for suppliers and material types are called-out consistently and typos are avoided. However, I would like to add the following functionality:
-If a new value is entered into the combo box the user will be prompted to fill out the necessary information on the new value. This information will subsequently be saved to the appropriate linked datasheet.
How would I go about setting up the prompt from the combo boxes themselves? It would require Access to open a form or sub-form that will, in turn, save to the linked datasheet.
I'd prefer it to be automatic, instead of end-user prompted so that it isn't skipped. It's been years since I played around with VB, so I would like to avoid that if possible and use Access' built-in functions (even if it requires a little more time). Thank you in advance!
Alright, so I was able to do it after researching the "OnNotInList" function and a little VB code.
In the OnNotInList section of the 'Event' properties sheet, I chose 'Code Builder' and entered the following:
Private Sub Supplier_NotInList(NewData As String, Response As Integer)
Dim ctl As Control
Dim dbsCustomerDatabase As Database
On Error GoTo Supplier_NotInList_Err
Dim intAnswer As Integer
Dim strSQL As String
intAnswer = MsgBox("The supplier " & Chr(34) & NewData & _
Chr(34) & " is not currently listed." & vbCrLf & _
"Would you like to add it to the list now?" _
, vbQuestion + vbYesNo, "Spire Manufacturing Solutions")
' Adding the new entry to the list:
If intAnswer = vbYes Then
strSQL = "INSERT INTO CustomerList([CustomerName]) " & _
"VALUES ('" & NewData & "');"
DoCmd.SetWarnings False
DoCmd.RunSQL strSQL
DoCmd.SetWarnings True
MsgBox "The new supplier has been added to the list." _
, vbInformation, "Spire Manufacturing Solutions"
Response = acDataErrAdded
' Opening the Supplier datasheet to add details
' to the new entry:
MsgBox "Opening Supplier database for new entry..."
DoCmd.OpenTable "CustomerList", acViewNormal, acEdit
End If
Supplier_NotInList_Exit:
Exit Sub
Supplier_NotInList_Err:
MsgBox Err.Description, vbCritical, "Error"
Resume Supplier_NotInList_Exit
End Sub
This allowed me to automatically prompt the user to add the details for a new supplier if they enter a new supplier name. Or, cancel the entry if they simply misspelled it. I'd quite forgotten how versatile VB was. Thank you all for your assistance in getting me headed in the right direction!

DoCmd.DeleteObject acTable - "could not lock table because it is already in use"

I'm getting the following error when trying to delete a table:
Run-time error '3211'
The database engine could not lock table 'RuleViolations1516' because
it is already in use by another person or process.
Here is the offending procedure, with a comment showing the line throwing the error:
Public Sub ImportRuleViolations()
DoCmd.Close acForm, "frmImportRuleViolations"
If _
TableExists("RuleViolations1516") = True _
Then
Debug.Print "Table RuleViolations1516 already exists"
DoCmd.DeleteObject acTable, "RuleViolations1516" ' <-- EXECUTION STOPS HERE
Debug.Print "...old table deleted..."
DoCmd.TransferSpreadsheet acTable, _
10, _
"RuleViolations1516", _
Forms!frmImportRuleViolations.txtRuleViolationsPath & Forms!frmImportRuleViolations.txtRuleViolationFile, _
-1
Debug.Print "...new data imported."
ElseIf _
TableExists("RuleViolations1516") = False _
Then
Debug.Print "Table RuleViolations1516 does not already exist"
DoCmd.TransferSpreadsheet acTable, _
10, _
"RuleViolations1516", _
Forms!frmImportRuleViolations.txtRuleViolationsPath & Forms!frmImportRuleViolations.txtRuleViolationFile, _
-1
Debug.Print "...new data imported."
End If
Dim db As DAO.Database
Dim tDef As TableDef, fld As DAO.Field
Set db = CurrentDb
db.TableDefs.Refresh
' LRN
Set tDef = db.TableDefs("RuleViolations1516")
Set fld = tDef.CreateField("newLRN", dbText, 20)
fld.OrdinalPosition = 2
tDef.Fields.Append fld
db.Execute _
"UPDATE RuleViolations1516 Set newLRN=[Learner Ref]", dbFailOnError
' delete old field
tDef.Fields.Delete "Learner Ref"
tDef.Fields.Refresh
' rename new field
tDef.Fields("newLRN").name = "LRN"
tDef.Fields.Refresh
Set fld = Nothing
Set tDef = Nothing
' AimRef
Set tDef = db.TableDefs("RuleViolations1516")
Set fld = tDef.CreateField("newAimRef", dbText, 20)
fld.OrdinalPosition = 7
tDef.Fields.Append fld
db.Execute _
"UPDATE RuleViolations1516 Set newAimRef=[Aim Reference Number]", dbFailOnError
' delete old field
tDef.Fields.Delete "Aim Reference Number"
tDef.Fields.Refresh
' rename new field
tDef.Fields("newAimRef").name = "AimRef"
tDef.Fields.Refresh
Set fld = Nothing
Set tDef = Nothing
Set db = Nothing
DoCmd.OpenForm "frmImportRuleViolations"
End Sub
The offending sub also makes reference to another function:
Public Function TableExists(name As String) As Boolean
TableExists = DCount("*", "MSysObjects", "Name = '" & name & "' AND Type = 1")
End Function
The above sub and function run on their own separate module (not tied to a form module).
The table RuleViolations1516 is not open when I run the sub. The form frmImportRuleViolations uses the RuleViolations1516 table in some queries behind some subforms, but as you can see from the sub, I've closed this form on the first line.
Any pointers would be appreciated.
Update:
frmImportRuleViolations has 2 subforms on it... removing them (temporarily) stops the issue. I need the subforms on the form though.. how can I get around this?
As I understand your updated question, you have a form called frmImportRuleViolations and that has a subform I'll call frmImportRuleViolationsSubform1.
frmImportRuleViolationsSubform1 references the RuleViolations1516 table somewhere on it.
I'm assuming you are also triggering this reload from a button or other control on frmImportRuleViolations. If so, then that makes sense as the cause of your error. Access may not have given up every reference to RuleViolations1516 by the time it gets to the close event.
That and a form closing and reopening itself can get kind of hairy.
One fairly easy thing to do would be to drop and load the table before the frmImportRuleViolationsSubform1 is opened. As a user (and a developer) that's what I would expect - I open the form and it's right up to date. And worst case situation closing the form and re-opening it gives me a refresh.
Failing that (it absolutely has to be reloaded after the form is closed); then I would make whatever is closing it open frmImportRuleViolations as a modal window, and then put reload of the table code after the call to frmImportRuleViolations since it will wait until control is returned to the calling window.
You could also instead load the data into a temporary staging table, and then delete the contents of RuleViolations1516 and repopulate it from the staging table. This would probably be the route I would take as it would eliminate the closing and opening of the frmImportRuleViolations form. You'd just have to tell the table on the sub-form to refresh (which I'll leave an an exercise for the reader).
Aside from that, a couple style notes:
'' this
If _
TableExists("RuleViolations1516") = True _
Then
'' could be equally written as
If TableExists("RuleViolations1516") Then
'' the "= True" is implied and not required
And
'' this
ElseIf _
TableExists("RuleViolations1516") = False _
Then
'' is redundant to the previous if. A simple else would do, since we
'' know if the last time it ran, it wasn't true, it must be false
And the DoCmd block looks like it does the same thing in both the if and else, so I'd be inclined to extract it like this:
If TableExists("RuleViolations1516") then
Debug.Print "Table RuleViolations1516 already exists"
DoCmd.DeleteObject acTable, "RuleViolations1516"
Debug.Print "...old table deleted..."
else
Debug.Print "Table RuleViolations1516 does not already exist"
end if
DoCmd.TransferSpreadsheet acTable, _
10, _
"RuleViolations1516", _
Forms!frmImportRuleViolations.txtRuleViolationsPath & _
Forms!frmImportRuleViolations.txtRuleViolationFile, _
-1
Debug.Print "...new data imported."
That way when you come back to change the name of the file (or whatever) you are only changing it in one place, etc. and goes along with the DRY principle - "DRY - don't repeat your self".
I like the use of underscores so that what you have coded does not run off the edge of the screen like some extract from war and peace. It makes it much more readable.
What you've done is not wrong. It's just not what most developers would do. And as much as we write code for the computer to function the way we want, we also want the next developer to touch your code 5 years down the line to easily understand what you are doing. And code always lasts longer than you think it will :^)
Good luck!

Auto Populate Access Form using simple VBA code by setting a variable

I was recently given the task of creating a form that will autofill with the information from a table. The information the form autofills is selected using a primary key called ModID. I have a combo box that has a List of the ModIDs that are listed as Active.
SELECT ModID
FROM P_Review
WHERE Status = "Active"
Simple enough. I then have VBA code running on the event After Update. So after the value for the combo box is select or changed it will run this VBA code.
Option Compare Database
Option Explicit
Private Sub selectModID_AfterUpdate()
'Find the record that matches the control.
On Error GoTo ProcError
Dim rs As Object
Set rs = Me.RecordsetClone
With rs
.FindFirst "ModID=" & Me.selectModID
If Not .NoMatch Then
Me.Bookmark = .Bookmark
Else
DoCmd.RunCommand acCmdRecordsGoToNew
Me!localModID = Me.selectModID.Column(0)
End If
End With
ExitProc:
Exit Sub
ProcError:
MsgBox "Error: " & Err.Number & ". " & Err.Description
Resume ExitProc
End Sub
The code runs fine (I get no errors when I debug or run).
Now for the access text box. I would like to populate certain fields based off the variable localModID. I have a dlookup in a text box to find the information in the table P_Review.
=DLookUp("Threshold","P_Review","ModID =" & [localModID])
So the DlookUp should find the value for the column threshold, in the table P_Review, where the ModID in P_Review equals the localModID set in the VBA code. But when I go to form view and select a ModID I get the Error 3070: The Microsoft Access database engine does not recognize as a valid field name or expression. I did copy this code from another database we are already using but it fails in this new instance.
Private Sub ModID_AfterUpdate()
Dim rs As Object
Set rs = Me.RecordsetClone
With rs
.FindFirst "ModID='" & Me.ModID & "'"
If Not .NoMatch Then
Me.Bookmark = .Bookmark
Else
DoCmd.GoToRecord , , acNewRec
Me!ModID = Me.ModID
End If
End With
End Sub
This is the answer to question. I used this code to auto update.
Try
Forms!<whatever_this_form_name_is>![localModID]
in your DLOOKUP