copy data from Form and Subform - ms-access

My Form shows only a record per time. Data are read from 2 tables ([Data Processing List] and [Attributes]). In the Form there is a Subform that gets data from a third table ([Security Measures]) and shows only the rows related to the record selected in the Form.
In the Form I have the button Copy whose aim is to duplicate the selected record.
The problem is that it duplicates only data of the 2 tables of the form and not the one of the Subform.
Did I do something wrong?
The code of the Copy button is the following (simplified):
Private Sub Copy()
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdCopy
DoCmd.RunCommand acCmdRecordsGoToNew
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdPaste
End Sub

This won't stay so basic when the subform records need to be copied too - Copy/Paste always affects only the current/select record of the active form.
You need to first store the old ID, then copy the main records, read the new ID, and then use these two IDs to copy the subform records.
Something like this (air code):
Private Sub Copy()
Dim OldId As Long, NewId As Long
Dim S As String
' Read old ID
OldId = Me!ID
' copy main records
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdCopy
DoCmd.RunCommand acCmdRecordsGoToNew
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdPaste
' Read new ID
DoCmd.RunCommand acCmdSaveRecord ' not sure if needed
NewId = Me!ID
' Copy all records from old ID to new ID
' TODO: add missing columns
S = "INSERT INTO [Security Measures] (ID_SM, System, Note) " & _
"SELECT " & NewId & " AS ID_SM, System, Note " & _
"FROM [Security Measures] WHERE ID_SM = " & OldId
Debug.Print S
Stop
' Hit Ctrl+G, copy SQL from Immediate Window to a new query
CurrentDb.Execute S, dbFailOnError
' Load copied records
Me!mySubform.Form.Requery
End Sub
BTW, [Security Measures] should really have a Primary Key on its own.

Or you can skip all the DoCmd stuff completely and operate directly on the recordsets of the forms:
First copy the parent record
Then copy the child records
Duplicate record and records in subform

Related

saving a record after deletion

I have a form to add a record for my users. The database will automatically add an ID to the record, after it's added with the user clicking a button on the form.
I also have a user activity log. I want to record the record's automatically generated ID number when the form adds a record. How do I access that number from the onClick event of the form?
Private Sub btnAddTax_Click()
Dim SQL As String
SQL = "INSERT INTO tblMain ( field1, field2,... )" _
& "SELECT Forms![field1Box], Forms![field2Box],...;"
DoCmd.RunSQL SQL
MsgBox "Tax Added to the Database"
DoCmd.OpenForm "frmMainScreen"
DoCmd.Close acForm, Me.Name
Dim tempString As String
tempString = "Added a record"
Logging (tempString)
End Sub
Consider code in button click event:
DoCmd.RunCommand acCmdSaveRecord
Debug.Print Me!ID 'or do something else with ID

Deleting record on Continuous form in MS Access using acCmdDeleteRecord

I have continuous form with just 2 fields and a button.
Design View
'
Form View
Below is the code for Delete Button.
Private Sub cmdDelete_Click()
DoCmd.RunCommand acCmdDeleteRecord
Debug.Print "IDWeb - " & Me.IDWeb
'Here I Execute a Web API to Delete Data based on Me.IDWeb
End Sub
The Problem - Web API does not get the Me.IDWeb Value . SOme times the IDWeb is captured correctly, sometimes not.
Edit1 : I tried the code below. But still the problem exists.
I guess the users can be on another record when they deleted the current record. Hence the issue. But the record is currently deleted in MS Access. Only the problem is Me.IDWeb is NOT captured correctly, and hence my web API is getting failed.
Private Sub cmdDelete_Click()
Me.WebType.SetFocus
If Me.IDWeb = "" Or Me.IDWeb = vbNull Or Me.IDWeb = vbNullString Then
MsgBox "No Record Selected"
Else
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdDeleteRecord
Debug.Print "IDWeb - " & Me.IDWeb
'Here I execute my Web API to Delete based on Me.IDWeb
End If
End Sub
The solution was to first get Me.IDWeb and store it in a variable,
then run acCmdDeleteRecord afterwards.
Personally, I don't use DoCmd. You are trying to get the IdWeb of a deleted record.
Assuming your IDWeb is a number (if not use the appropriate data type), the following should work
Dim lngIdWeb as long
lngIdWeb = nz(Me.IdWeb, 0)
If lngIdWeb > 0 Then
Me.RecordsetClone.FindFirst "IdWeb = " & lngIdWeb
If Not Me.RecordsetClone.NoMatch Then
Me.RecordsetClone.Delete
End If
Debug.Print "IdWeb - " & lngIdWeb
End If

Access - Duplicate Record button creates a blank record

I've got a fairly simple database, 5000 records about 60-70 fields, and I created a button to copy the current record and blank out some of the fields (which we called EXPAND).
I recently received a requests to do the same thing without blanking out any fields but it doesn't work. I used the Command Button wizard on my form and chose the Duplicate option, but the new record is completely blank. Additionally, I get an error message when I close the record that talks about "A large amount of data copied to the clipboard". I tried the original button I had made (EXPAND) and it resulted in the same issue. Searching back through old records, I see that it was working as recently as 6/10/2016 (10 days ago).
Has something changed which would prevent this code from executing properly? Is there a new setting/option I need to enable to get it working again? Or is there some alternative method I can use to accomplish the same result?
Here is the (very simple) code the system created to duplicate the record (which doesn't work):
Private Sub cmdDuplicate_Click()
On Error GoTo Err_cmdDuplicate_Click
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdCopy
DoCmd.RunCommand acCmdRecordsGoToNew
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdPaste
Exit_cmdDuplicate_Click:
Exit Sub
Err_cmdDuplicate_Click:
MsgBox Err.Description
Resume Exit_cmdDuplicate_Click
End Sub
The fastest and simplest way is to use DAO and the RecordsetClone of the form:
Private Sub cmdDuplicate_Click()
Dim rstSource As DAO.Recordset
Dim rstInsert As DAO.Recordset
Dim fld As DAO.Field
If Me.NewRecord = True Then Exit Sub
Set rstInsert = Me.RecordsetClone
Set rstSource = rstInsert.Clone
With rstSource
If .RecordCount > 0 Then
' Go to the current record.
.Bookmark = Me.Bookmark
With rstInsert
.AddNew
For Each fld In rstSource.Fields
With fld
If .Attributes And dbAutoIncrField Then
' Skip Autonumber or GUID field.
ElseIf .Name = "SomeFieldToPreset"
rstInsert.Fields(.Name).Value = SomeValue
ElseIf .Name = "SomeFieldToExclude
' Leave blank
Else
' All other fields.
' Copy field content.
rstInsert.Fields(.Name).Value = .Value
End If
End With
Next
.Update
' Go to the new record and sync form.
.MoveLast
Me.Bookmark = .Bookmark
.Close
End With
End If
.Close
End With
Set rstInsert = Nothing
Set rstSource = Nothing
End Sub
I think the easiest way may to create an append query. Set the criteria field as the ID of the current record. This can be done pretty easily in the query design window.
No error message?
Do you have a Primary Key ID field on the form that doesn't allow you to copy duplicate ID?

Get recordset from selected records on datasheet

I have a subform with a datasheet view. On the parent form I am trying to edit records based on what is selected in the child datasheet. The forms are not linked using master/child fields.
I'm capable of getting the top row that is selected and the number of selected rows using SelTop and SelHeight like below.
Dim rs As New ADODB.Recordset
Set rs = Me.Child_Form.Form.RecordsetClone
If SelHeight > 0 Then
rs.MoveFirst
rs.Move SelectionTop - 1
For i = 1 To SelectionHeight
If Not rs.EOF Then
Debug.Print rs("ID")
rs.MoveNext
End If
Next i
End If
What I cannot do is get, say, the 10 records selected on the subform if I have filtered or sorted the form at all. The Filters and Sorts are at the form level and cannot be applied to the underlying recordset.
I've tried creating a new recordset with a query something like this
sql = "Select * from [" & Me.RecordSource & "] where " & Replace(Me.Filter, """", "'") & " order by " & Me.OrderBy
but there are multiple problems here. 1) ADO does not support the IN clause which the form filter will sometimes generate, and 2) the order order is not always the same and predictable.
How can I get a sorted, filtered recordset and find only those records which a user has selected in a datasheet view?
I am connecting to Sql Server with an ADP file.
I came up with a frustrating solution but it seems to work.
added an unbound (to my recordset) checkbox control to my subform.
named it chkSelect.
made the controlsource =IsChecked(ID)
I have this code running in the subform
Dim selectedRecords As Dictionary
Private Sub chkSelect_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If selectedRecords.Exists(Me("Analytical_ResultID").Value) Then
selectedRecords.Remove Me("Analytical_ResultID").Value
Else
selectedRecords.Add Me("Analytical_ResultID").Value, Me("Analytical_ResultID").Value
End If
chkSelect.Requery
End Sub
Private Function IsChecked(Analysis_ResultID As Long) As Boolean
IsChecked = selectedRecords.Exists(Analysis_ResultID)
End Function
Private Sub Form_Load()
If selectedRecords Is Nothing Then
Set selectedRecords = New Dictionary
End If
End Sub
This works but it's flickery and not ideal. I would much prefer another answer.

"Not a valid bookmark" with DAO Recordset

I'm in the process of converting an Access Data Project (ADP) into a standard ACCDB format with ODBC linked tables. In the ADP, I had overridden the Refresh button to return the user to the current record by using the following code:
Public Sub RibbonCmd_RefreshScreen(ctl As IRibbonControl, ByRef cancelDefault)
On Error GoTo ErrHandler
cancelDefault = False
DoCmd.Echo False
Dim saveBookmark
With Screen.ActiveForm
saveBookmark = .Bookmark
.Requery
.Bookmark = saveBookmark
End With
'Success - cancel the default behavior
cancelDefault = True
ExitHandler:
DoCmd.Echo True
Exit Sub
ErrHandler:
cancelDefault = False
Resume ExitHandler
End Sub
My understanding is that this should work just fine with DAO, but I get error 3159, Not a valid bookmark. I've also tried replacing .Bookmark with .Recordset.Bookmark, but that gave me the same result. Is there something I'm doing wrong here?
Actually, a requery of a form or a requery of a recordset will re-set and invalidate book marks.
So such book marks are no longer valid after a requery.
So the best approach here will depend on either
a) I simply want to re-display any changed records (and not move off current record).
b) I simply want to re-display any changed records AND ALSO display new records (the new records is the critical part).
If you just need a refresh, then you can use the appropriately called command refresh.
Eg:
Me.Refresh
Or in your case
Screen.ActiveForm.Refresh
So the above is ONE line of code and is ALL you need. The current record pointer for the form does NOT change when you use this command. All and any record changed will re-display for you.
Note that since you can behind the form button use:
Me.Refresh
Then LITTLE need is required to call a general routine as you have written.
However, if you need the form to "load" or display any new records added, then you DO have to use requery. In this case as noted book marks in this case all become invalid.
So, for code to requery, then we use the PK value (and hopefully you used the default pk of ID that been the default for 20 years). The code would then become:
Dim lngID As Long
If IsNull(Me!ID) Then Exit Sub
lngID = Me!ID
Me.Requery
Me.Recordset.FindFirst "id = " & lngID
Now of course if the PK id is not the same for each form, then you most certainly could pass the NAME of the PK value to your "general" refresh routine. It would look like:
Public Sub MyRefresh(strPK As String)
Dim lngID As Long
If IsNull(Me(strPK)) Then Exit Sub
lngID = Me(strPK)
Me.Requery
Me.Recordset.FindFirst strPK & " = " & lngID
End Sub
The "hope" here is you actually really JUST need refresh, since as noted this is only one line of code, and better yet it does NOT move the record pointer.
I use VB6 and Visual Data Manager in development. I have had the same problem. Most probably it arose when 2 users tried to update the same record in the same time. So some fields in the table are corrupted.
Here are the steps I used to solve the problem:
1- Copy the structure of the table (lets call it table1)to another table (lets call it table2).
2- Find the correpted record(s) in table1.
3- Transfer the data from table1 to table2 except the corrupted record(s)
4- Reenter the excluded record(s) to table2 again.
5- Rename table1 table3
6- Rename table2 table1
That's all folk
abdobox#yahoo.com
I have used the forms Recordset.AbsolutePosition, and this works fine e.g. in the OnKeyDown exit of a field
Dim PrefilterPosition As Long
Private Sub ValnSubject_KeyDown(KeyCode As Integer, Shift As Integer)
' Not F2 - exit
If KeyCode <> vbKeyF2 Then Exit Sub
' Get the active control
Dim ActiveCtl As Control
Set ActiveCtl = Me.ActiveControl
ActiveControlName = ActiveCtl.Name
' Is the form's filter set?
If Me.Filter = "" Then
' NO: Apply the new filter
' Note the current position in the recordset
PrefilterPosition = Me.Recordset.AbsolutePosition
' Set the filter to the Active control's value
Me.Filter = "[" & ActiveCtl.ControlSource & "]='" & ActiveCtl.Value & "'"
Me.FilterOn = Me.Filter <> ""
Me.Requery
Else
' YES: Clear the filter
Me.Filter = ""
Me.FilterOn = Me.Filter <> ""
Me.Requery
' Align the recordset on the previously stored position
Me.Recordset.AbsolutePosition = PrefilterPosition
End If
' Restore the cursor to where it came from
Me.Controls(ActiveControlName).SetFocus
Ex_it:
End Sub
For context: this code was from an idea for an 'Instant Filter', where you position the cursor on a field in a tab form, press F2, and then a filter is applied so you see only records with the selected field's value. Press F2 again and the filter is removed and the cursor goes back into the place it was when you hit F2 the first time. Bookmarks do not work here, as Albert says above.