Locking Previous Records in Access Database based on ID - vba

I am trying to build a code where previous records in a certain form are locked for editing. This would be to allow users to create and edit new forms, but not change data from previous forms. I want to be able to allow users to access and edit the previous 5 forms, but lock the data in all forms previous to that.
I've tried several things, but as a novice VBA user, nothing has worked. I tried:
Private Sub Form_Load()
If Me.ID < 22 Then
Me.AllowEdits = False
Else
Me.AllowEdits = True
End If
End Sub
I used a dummy "22" to see if the code would work, but it just ended up locking all of the records, not just numbers 1-21, like I was trying to do.
I would like the "22" to be the value of the ID field in the most recent record. I would also like it to be: If Me.ID < (ID of most current record)-5
Is this possible?

Form_Loadis wrong event, as only raised once on startup withMe.IDbeing the first record. You have to check current selected record withForm_Currentevent.
Don't rely onIDbeing consecutive (e.g. caused by deletions). Select Top 5 IDs (sort decending) and get minimum.
Create as saved query (e.g. name it FormNameTop5ID, where FormName is name of form, TableName is table/query bound to form )
SELECT TOP 5 ID FROM TableName ORDER BY ID DESC
In the form create aForm_Currentevent
Private Sub Form_Current()
If Me.ID.Value < DMin("ID", "FormNameTop5ID") Then
Me.AllowEdits = False
Else
Me.AllowEdits = True
End If
End Sub

Related

ms access updating field conditionally on form.activate

My question concerns situations where custom code is required to auto-increment fields in MS Access, specifically with issues that arise from using such code in the OnActivate event.
I have a field [Group_ID] that auto-increments each time a new record is made using custom code in the OnCurrent and OnActivate events. Sometimes I need Group_ID to be incremented OnActivate, but sometimes I do not. In some cases users will actually use a "duplicate record" button to use the same Group_ID (along with most other fields) for a subsequent record. In situations like these, I'd like to set a condition for the OnActivate event that allows users to reference other forms or tables without re-querying Group_ID upon returning to the form to finish a record. Here is my code:
'increments Group_ID when a new record is made
Private Sub Form_Current()
If Me.NewRecord = True Then
Me.Group_ID = Nz(DMax("Group_ID", "All_sightings"), 1) + 1
End If
End Sub
'increments Group_ID when the form becomes active IF the value is no
longer max value + 1
Private Sub Form_Activate()
If Me.Group_ID = Nz(DMax("Group_ID", "All_sightings")) + 1 Then
Else
Me.Requery
End If
End Sub
What I would like to do is add an additional condition to the Form_Activate sub that checks whether a different field is already filled out (e.g. if the "duplicate" button was used) when the form re-activates after a user returns to a partially completed record. This field will not require any input from the user because it will be automatically filled when a user clicks the duplicate button. The field I have chosen is [UTM_x].
I have tried:
=IIF(Me.Group_ID = Nz(DMax("Group_ID", "All_sightings")) + 1 And Not IsNull(Me.UTM_x), "", Me.Requery)
And various other combinations of nested IIF() and IfThenElse statements, but have not had any luck. The form continues to requery every time on the OnActivate event when Group_ID is not more than (max+1). Any suggestions?
I played around with iif statements and more if-then-else statements, eventually finding a solution to my problem. Here it is:
Private Sub Form_Activate()
If Me.Group_ID = Nz(DMax("Group_ID", "All_sightings")) + 1 Then
'blank/do nothing because Group_ID is already max+1
ElseIf IsNull(UTM_x) Then
Me.Requery 'makes Group_ID max+1 because null UTM_x means it's a new record
Else
'blank/do nothing because Group_ID = max and this is a duplicated record
End If
End Sub

Filtering controls on subforms after selecting criteria from another form

I have three subforms I'd like to filter - we'll call them Customers, Items and Employees. I want to sort them based on a 4th form, Addresses, after double-clicking on the Address_ID. So essentially disable those forms until an Address_ID is selected and then populate them based on the given address.
The trouble is that I'm not sure where or what to code. I would assume that I need to create a Double_Click event on the Address_ID control. Maybe store that ID into a variable and somehow pass it to the parent form where the other 3 forms can reference it?
Problem is I have no idea how to accomplish that or if it will work at all.
You can a Form_Current event on the address sub form and update the recordsources (not recordset) from each of the subforms. This is my personally my preferred approach, but there a plethora of options available to approach this situation. Here's a sample code on how you could approach this.
Private Sub Form_Current()
Dim addressID As Integer
Dim sql As String
If IsNull(Me.addressID.Value) Then
'disable subforms
Form_frmHome.sbfCustomer.Enabled = False
Form_frmHome.sbfEmployee.Enabled = False
Form_frmHome.sbfItem.Enabled = False
Else
'enable subforms
Form_frmHome.sbfCustomer.Enabled = True
Form_frmHome.sbfEmployee.Enabled = True
Form_frmHome.sbfItem.Enabled = True
addressID = Me.addressID.Value
'Customers
sql = "SELECT * FROM tblCustomers WHERE AddressID = " & addressID
Form_frmHome.sbfCustomer.Form.RecordSource = sql
'Employees
sql = "SELECT * FROM tblEmployees WHERE AddressID = " & addressID
Form_frmHome.sbfEmployee.Form.RecordSource = sql
'Items
sql = "SELECT * FROM tblItems WHERE AddressID = " & addressID
Form_frmHome.sbfItem.Form.RecordSource = sql
End If
End Sub
Expand the Master/Link child fields of the three subform controls to include the Address_ID of the fourth:
[NameOfTheFourthSubformControl].Form!Address_ID
and the three subforms will be filtered automatically (zero code) to the current Address_ID.
NameOfTheFourthSubformControl is the control on the parent form, not the name of the subform itself.

How to create Access User Form to both look up and add data

I have an access form that contains two subforms. The main form has three dropdown fields that allow the user to pick what data is displayed in the two linked subforms. The dropdown fields are all unbound as they are referenced in the datasource of the main form.
The SQL of the datasource for the main form is as follows:
SELECT tbl_RptPeriod.RptPrdID, tbl_BusUnits.UnitID, tbl_Categories.CategoryID, tbl_Categories.CategoryTitle, tbl_Categories.CategoryGroup, tbl_Categories.Inactive, tbl_Categories.RptPrdID, tbl_Categories.UnitID
FROM tbl_RptPeriod INNER JOIN (tbl_BusUnits INNER JOIN tbl_Categories ON tbl_BusUnits.UnitID = tbl_Categories.UnitID) ON tbl_RptPeriod.RptPrdID = tbl_Categories.RptPrdID
WHERE (((tbl_RptPeriod.RptPrdID)=[Forms]![Compliance]![cmbReportPeriod]) AND ((tbl_BusUnits.UnitID)=[Forms]![Compliance]![cmbBusinessUnit]) AND ((tbl_Categories.CategoryID)=[Forms]![Compliance]![CategoryTitle]));
This works perfectly to look up records. However, I want the users to be able to add new records to the ones they are looking up. That doesn't work as it should.
I can add records, but then the form elements that I am using to look up the data, specifically RptPrdID,UnitID, and CategoryID are not being populated in the table, thus the new records are unassociated and don't show up if you go to look for them again in the main form after closing it or moving to another record.
This makes sense in so far as the form elements I am using in the "WHERE" criteria of the SQL are unbound, but of course, if I add a new record, I want it to be correctly matched. The user must be able to find the records he adds if he looks up the same criteria again.
Question:
How can I get new records entered in the subforms to have RptPrdID,UnitID, and CategoryID filled in?
UPDATE
SELECT tbl_Activity.CategoryID AS CategoryID_X, tbl_Activity.RptPrdID AS RptPrdID_X, tbl_Activity.UnitID AS UnitID_X, tbl_Categories.SortKey, tbl_Categories.CategoryTitle, tbl_Categories.CategoryGroup, tbl_Categories.Inactive, tbl_Categories.Inactive, tbl_BusUnits.Unit_Name, tbl_RptPeriod.Rep_Month_Nr, tbl_RptPeriod.Rep_Month_Name, tbl_RptPeriod.Rep_Year
FROM tbl_RptPeriod INNER JOIN (tbl_Categories INNER JOIN (tbl_BusUnits INNER JOIN tbl_Activity ON tbl_BusUnits.UnitID = tbl_Activity.UnitID) ON tbl_Categories.CategoryID = tbl_Activity.CategoryID) ON tbl_RptPeriod.RptPrdID = tbl_Activity.RptPrdID
WHERE (((tbl_Activity.CategoryID)=[Forms]![Compliance_EXPERIMENT]![cmbCategoryTitle]) AND ((tbl_Activity.RptPrdID)=[Forms]![Compliance_EXPERIMENT]![cmbReportPeriod]) AND ((tbl_Activity.UnitID)=[Forms]![Compliance_EXPERIMENT]![cmbBusinessUnit]))
ORDER BY tbl_Categories.SortKey;
I had to change the query somewhat, but the key fields are still the same ones, though they are now on a different table.
Private Sub Form_BeforeInsert(Cancel As Integer)
Me.RptPrdID_X = Me.cmbReportPeriod
Me.UnitID_X = Me.cmbBusinessUnit
Me.CategoryID_X = Me.cmbCategoryTitle
End Sub
Add code for filling those 3 fields in Before Insert event of main form
Private Sub Form_BeforeInsert(Cancel As Integer)
Me.RptPrdID = Me.cmbReportPeriod
Me.UnitID = Me.cmbBusinessUnit
Me.CategoryID = Me.CategoryTitle
End Sub

Hide Delete Button in Gridview if RowID links to Foreign Key [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
VB.NET - I've found other questions related to this, but none specifically to my situation. I'm dealing with only two tables - "task" and "task_run."
I have a Gridview with rows listing certain "tasks." They come from the "task" table and each task has a "tsk_id." I want to have a delete button for each task (row) and only want the delete button visible for that row if the task does not have a run associated with that task from the "task_run" table. (i.e. I do not want the user to be able to delete that task if it has already been run.)
table1 - "task"
PKY = "tsk_id"
table2 - "task_run"
PKY = "run_id"
FKY = "run_tsk_id"
I assume I need to have a template field in my gridview and have the delete button conditionally show based on whether there are rows in the run table associated with that particular task Id, but am stuck on how to do this. Hopefully this makes sense. Any help is appreciated. Thanks!
You first get the task_Id from Task_run table accordingly user if exist otherwise return zero value , and placed this Task_Id in gridview on Label or textbox or hidden field with visible=false property if you not showing to user,
use this command for checking Task have already run or not by user.
SELECT ext.* , ISNULL((SELECT top 1 run_tsk_id
FROM task_run WHERE run_tsk_id = ext.tsk_id),0) AS CheckId
FROM task ext
then use the gridview RowDataBound event to hide or show the delete button conditionally, code as.
Protected Sub Grid_RowDataBound(sender As Object, e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim lblCheckId As Label = DirectCast(e.Row.FindControl("lblCheckId"),Label)
Dim deleteButton As Button = DirectCast(e.Row.FindControl("btnDelete"), Button)
If CInt(lblCheckId.Text) > 0 Then
deleteButton.Visible = False
Else
deleteButton.Visible = True
End If
End If
End Sub
If you already have your tables in a DataSet (ds say), you can add a relation via
ds.Relations.Add(name, parentColumn, childColumn, createConstraints)
For example:
ds.Relations.Add(
name,
ds.Tables("task").Columns("tsk_id"),
ds.Tables("task_run").Columns("run_tsk_id"),
True)
Alternatively, you could add a "task_run_count" as a property of table task via a subquery:
SELECT ...,
(SELECT COUNT(*) FROM task_run WHERE run_tsk_id = task.tsk_id) AS [task_run_count]
FROM task
The DataSource which you are binding to to the grid should also have Task run count. Then you can use the RowDataBound event to show or hide the button.
Protected Sub Grid_RowDataBound(sender As Object, e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim taskRunCount As Integer = Convert.ToInt16(e.Row.Cells(0).Text) ''The Cells[0] should be which ever column you have Task run count
Dim deleteButton As Button = DirectCast(e.Row.FindControl("DeleteButton"), Button)
If taskRunCount > 0 Then
deleteButton.Visible = False
Else
deleteButton.Visible = True
End If
End If
End Sub

Check if record already exists in table Access 2010 VBA

I have created a table in Access 2010 that holds a list of employee names, using an ID as the primary key.
I have another table which uses these names as a foreign key, via the ID, in a drop down box, which allows users to select an employee's name, and then record training to that name using a form.
What I would like to ask is, how would I write the VBA code that would check if an employee's name had already been added to the training table, thus checking if an employee had already completed that training, and then return a message box alerting the user; "This employee has already completed their training, are you sure you want to proceed?"
I am relatively new to VBA, however I assume I need some sort of Count method on the employee ID. Thanks in advance!
I figured it out, thanks for your help!
'Save button
'Activated on click
'Runs macro if that employee has not already been added to the WelfareTraining database
Private Sub SaveRecord_Click()
Dim stDocName As String
stDocName = "SaveRecordTraining"
If DCount("[Employee]", "WelfareTraining", "[Employee] = " & Me![Employee] & " ") > 0 Then
MsgBox ("This employee has already completed their training")
Else
DoCmd.RunMacro stDocName
End If
End Sub