views:

41

answers:

2

With this kind of design, I would like to create a functionality with which to add and delete records from the junction table.

The case is from when editing an employee and selecting what exams they can take. In the left list box would be the exams that they aren't eligible for (yet, anyway) and the exams that they are eligible for on the right list box.

The table is something like this:

TABLE EmpExam 
(
  EmpID,
  ExamID
)

The EmpID would be known at all times, but the ExamID would be selected from the left list box. Records in the right list box would probably have to have both the EmpID and the ExamID in order to be deleted.

Instant deletions/insertions aren't necessary once they're into their respective boxes are not necessary (they can wait until the form is closed).

Is there a good/standard way to accomplish this in Access?

+1  A: 

Why use listboxes when you will have to add items to the table using code and then delete them using code?

For what you want to do, a subform is the usual solution. Furthermore, you can use the recordsetclone of your subform. Note that you should probably have a datetime field in that setup. Also, if ExamID is unique, and cascade delete is enabled, deleting from the main table will delete from the subtable.

Remou
You mean, if I delete from the Exam table, then the EmpExam entry gets deleted too? If so, then that's what I intended and have set up. Also, is there a good tutorial on what you're suggesting?
Nitrodist
Yes, but it does come with a warning: http://www.granite.ab.ca/access/cascadeupdatedelete.htm, however, in this case it is probably suitable. Here is a tutorial: http://office.microsoft.com/en-us/access-help/delete-one-or-more-records-from-an-access-database-HA001173951.aspx
Remou
Note that if you run a delete query you may not get the warning that you are about to delete from more than one table.
Remou
You are aware are you not, that you can create the subform bound to the junction table on EmpID with just one combobox that has the exam list as its row source and ExamID as its bound column. This will give you a great deal of control, including the ability to prevent the addition of rows beyond the exam question count by checking that the recordset.recordcount is less than or equal to exam count?
Remou
Yeah, you definitely don't get a warning if you use the CurrentDb.Execute method.
Nitrodist
I've upvoted @Remou's answer, but let me just emphasize that this is the usual approach to editing junction tables in an Access application. It operates directly on the data tables, so no code is necessary to do the inserts/deletes. It's also the whole point of Access -- bound forms are where you should always start when you want to edit data in an Access application, no matter what that data is.
David-W-Fenton
I went with my solution because I don't quite understand how this could be implemented with comboboxes and a subform *as clearly* to the user as to which exams they have and which exams they don't have.
Nitrodist
Hmm, with the way I went, trying to add exams with a new employee record is impossible since they don't have their ID until they're created. Would the subform solve this problem by updating those subform entries to the proper ID once the employee record is created?
Nitrodist
Once you move from the main record to the subform, the main record is saved and the Link Child Field is set to the Link Master Field. Your combobox can list only exams that have not been taken, if you wish.
Remou
Life gets much easier if you follow the Way of Access :D
Remou
Or is there a way to just have it save right away? i tried `DoCmd.Save` on form open, which is fine, it allows me access to the ID field, but it still hasn't saved the record so the table's consistency check fails (silently, since I'm doing it through `CurrentDb.Execute`)
Nitrodist
Use `If Me.Dirty Then Me.Dirty = False` to force a save before you execute anything.
Remou
A: 

I ended up using two listboxes with 1 add button and 1 remove button that triggers their VBA On Click methods that execute raw SQL.

The method looks something like this:

If IsNull(cboInEligible.Column(1))
  Exit Sub
End If

CurrentDB.Execute ("INSERT INTO tblEmpExam (ExamID, EmpID) " & _
                   "VALUES (" & ExamID & ", " & lstInEligible.Column(1) & ")")

lstInEligible.Requery
lstEligible.Requery

The delete query is similarly done.

The two listboxes are mutually exclusive.

SELECT EmpID, EmpName
FROM Employee
WHERE EmpID NOT IN (SELECT EmpID FROM tblEmpExam WHERE ExamID = [txtExamID]);

txtExamID is a hidden (but obvious to the designer) control on the form since I can't refer to the form's ExamID except through a control or through absolute naming.

The other list box has EmpID IN instead of EmpID NOT IN to make it exclusive.

Nitrodist