Access Forms - Catch 22 trying to insert data to multiple related tables - ms-access

I'm new to Access but have many years experience using "enterprise" databases. I'm having trouble implementing a simple task and suspect that my preconceptions are causing me to miss the point so I'm asking for some help.
The simple task is using Access forms for Data Entry that populates two tables: Customer and CustomerAddress (can be multiple addresses per customer).
The Customer table has primary key CustomerID. The CustomerAddress table has primary key CustomerAddressID and CustomerID as a foreign key with RI on that relationship.
Form1 is bound to the Customer table. After entering info for various fields, the user can click a button to display Form2 which is bound to CustomerAddress and enables data entry for multiple addresses.
Form1 passes the CustomerID (assigned by Access) to Form2. Form2 is not a subform due to size but it could be if that would solve the problem.
In a perfect world, I would want all the new data from both Form1 and Form2 to be committed together. Presumably I could do this using unbound forms and code the insert statements inside a single transaction.
Question 1: Is there a way to do this using bound forms?
If I use Form1 without ever clicking the "Address" button then a row is successfully added to the Customer table. The problem comes when trying to add CustomerAddress row(s) in Form2 before the Customer row has been added to the table.
In Form2, if the CustomerID is not used, then there is an insert error because a CustomerAddress row cannot be added without a CustomerID.
If the CustomerID is used, then there is an insert error because the CustomerID does not exist on the Customer table yet (although the ID appears to have been "reserved").
It's not practical to force the Customer row to be added before opening Form2 as some Customer required fields are not present at that point in the workflow.
Question 2: Is there a way round this? It seems like a common requirement.
I could work around this by removing the RI so that the CustomerAddress rows can be added first, but this seems poor DB design and I'd also need clean-up logic for the case where the Customer add is subsequently cancelled.
As mentioned, I'm probably missing the point and there's a better approach. Any help much appreciated.

I think you would have the same problem regardless of which RDBMS you used if you are enforcing referential integrity. The CustomerID needs to exist in the Customer table before a record can exist in the CustomerAddress table. I'm guessing that CustomerID is an autonumber. What is probably confusing is that Access does immediately 'reserve' an autonumber as soon as a new record is started. However, it does not exist in the Customer table. If that record is never saved, that autonumber value is lost and the next record would get the next number. Requiring an address to be completed before saving the Customer record, sounds like a design problem. It doesn't seem logical. Personally, I would re-think the design. That said, one solution would be to create a temp table for addresses and bind your CustomerAddress form to that. Then, when the customer record is saved, you would run an append query to add the new addresses to the CustomerAddress table. Remember, though, that if a user enters some addresses and the Customer record is never saved, all of that data entry is lost.

With regard to your statement:
It's not practical to force the Customer row to be added before opening Form2 as some Customer required fields are not present at that point in the workflow.
You are correct that you won't be able to insert the Customer row if the "required but not yet known" fields have their Required property set to Yes (i.e., NOT NULL). However, with Access 2010 and later you could use an event-driven data macro to make such fields "not required" on Insert but "required" on Update. In your case, you could
allow the Customer record to be inserted without the "eventually required" fields,
allow the addition of CustomerAddress records (with RI enabled), and then
re-open the Customer record for updating, with the data macro now enforcing the "required" status of the other fields.
The Before Change data macro might look something like this:

I think the answer lies within your Question 1. Yes there is a way to do this with bound forms, and would be the approach I would use.
Form1 is bound to the Customer table. Add Form 2 onto Form 1 as a subform. Select / highlight Form 2, goto the properties sheet. On the Data tab, set the Link Master Field to CustomerID and Link Child Fields to CustomerID.
Then after any action taken on Form 1, requery Form 2.
I think this will get you started and at least should give you an idea on how to proceed once completed.

I fail to see why both must be or one would even want to submit both customer and a record from the child table at the same time.
What about when you want to add an additional address, then that add address button and code now will have to check + test if the main customer already exists, and use separate logic to deal if the customer record exists, or does not. And what about if a user has entered the customer name and info, and does not yet have the address as the customer on the phone might have just moved and has to call back with the new address. I can think of another half dozen cases in which building a design in which both customer and customer address records MUST be added at the same time.
As others noted, you going to have this issue with any relational database, including Access. I should also point out that Access works EXACTLY the same here if you use Access as a front end to SQL server or Oracle.
So it makes little sense to build a different UI and coding process for adding the customer and the address, and then a DIFFERENT set of rules and UI for adding additional address over time. So build a form to search + find a customer, and add that customer and display that customer. Once that process is done, then you add the process (and UI part) to allow the user to view, or add address to that customer. I don’t think I ever seen a UI with separate forms to add/edit customer and a separate form to allow additional address to have some requirement that they are submitted together at the same time.
If the user bails out of the Address because they realize the address is not available, wrong etc., this should not suggest that the customer information entered so far be dumped and not added. If the user after bailing from adding the address (say close or cancel that form), then you return to the customer form. If the user decides at that point in time for some strange reason they do NOT want the customer in the system anymore, then provide a delete button.
If the business rules are that one MUST ALWAYS have at least one address in all cases, then upon closing the customer form you don’t allow the form to be closed and request that that user enter at least one address for this user. And perhaps they bumped or hit the wrong key to exit the address enter part – no need to penalize that user and force them to re-enter the customer info. So don’t let them exit the customer form until they enter an address or provide them (suggest to the user) they can delete/remove the customer fi they want to exit.
If you use a form + sub form setup, then zero code is required for the relational part. And a tab control gets you both forms can be near full screen size. (no need to launch a separate form).
Of course you could write a bunch of code and placed everything in a transaction, but such is a waste of coding time for no benefits and amounts to theft of company hours and time when not required.

Related

how to assigne correct client_ID to order record from name, adress or create a new one if it doesn't exist

I am trying to build a simple ms Access database.
For the sake of convenience, I will translate into sales, orders and such.
Orders
OrderID - PK (auto number)
Client ID - FK to clientID in the Clients table
Clients
ClientID - PK (auto number)
LastName
FirstName
Company
Address
...
I created a form (main form) that allow the user to specify details for a new order, including the client details.
The same form is used to look the details of older orders, to change their step for instance.
When the clerks types in, I don't know if the client is already registered. After everything has been completed, the clerk saves the new order as a new record in the Orders table.
However, Access complains rightly that the clientID FK has not been set: we set the clients name, first name... but not the ID.
My ultimate goal is that, at the saving of the new record, a request that look up into the Clients table to identify a list of possible candidates that match the client first and last name and open a form (contact form) that nicely displays the data from the first record of the request and allow the clerk to navigate between the records, and eventually select one or select create new record with the data from the main form.
I figured that a good place to do this would be in the save button on my form.
I tried to add something in the event code (macro) with something like (not VBA, a pseudo code I've never seen in the other office applications):
if IsNull([main form]![clientID]) then
bip
launch a request to identify the clients in the clients table with the same first and last name
open a form to look into each selected record and select the correct one or if none is identical generate a new one and return the clientID
end if
executeMenuCommand
command saveRecord
The code I tried above didn't even bipped...
I have placed the bip first, and that didn't bipped either.
I receive a message (explicit) that ms Access could not find a record in the client table with the specified clientID.
So I guess my main question is how do I test if there is a clientID associated with the current record?
The next problem is to come back to the main form with the selected clientID.
From what I have seen in the templates provided by Microsoft, it is avoided by defining a single field for customer in their main form. This field is a list populated from the client table, and if you stray away from the list you get a new form for editing a new client.
This is not the behaviour I am looking into. I need to have the posibility to free text enter every field and chose at the saving moment to create or not a new customer.
I hope I am clear enough, please feel free to ask for more details.
edit: thanks to Gustav's hint, I figured that the event was not to be associated with a button click but on the form itself. It helped me uncover other underlying problems... so I guess my problem is not ripe anymore for soliciting external help.
In VBA, use IsNull, and Me if the form is bound to table Orders:
If IsNull(Me![clientID].Value) Then

How to save row values from one field in subform to main form record? - Access

I have a parent form (frmGroupSession) that has a subform (SubFormParticipants) in datasheet view. The subform is based off a query that selects all participants ([CLIENT ID], [NAME], [ATTENDED]) that had attended a specific group [GroupID] on a specific date [GroupSessionDate]. The parent form saves to a table that logs group sessions (tblGroupSessionLog). I need to save the group's participants [CLIENT ID] to the record within tblGroupSessionLog
Basically, I need to pass data from the subform to the record within tblGroupSessionLog. I'm not sure what the most effective way to do this, if it's possible at all. Ideally, I would like to have each unique participant [CLIENT ID] stored in its own field within tblGroupSessionLog. If there were 20 participants in the subform then each row value from the first column/field [CLIENT ID] would be passed to the corresponding field within tblGroupSessionLog ([ClientID1] thru [ClientID20])
I am relatively new at this. Even asking the question was difficult.
I am not sure what else I can provide to help you wizards with the solve, but let me know and I will.
Thoughts? Ideas?
Access 101 : You have a many to many relationship You should look that term up but in short it means clients can belong to many groups and each group can have many clients. (so bang your data into a normalized structure similar to the following:
First tip make sure to add the relationships under database tools (you should look that up). Access needs to know how the tables are related to manage the keys behind the scenes and sometimes access makes better decisions about automatic form creating when it already knows the relationship structure. Once your data is properly structured access makes it easy to produce functional if much less than styling data entry forms which can also be used as even worse search forms. For instance Click on any table and hit create form on the ribbon and access will create the data entry form form you.
Basic Style tip 1: Always delete primary key fields like ClientID from the form. The field is still there in the form's record source being managed by access. Users almost never need to see any table keys. This gives you a basic data entry form which you can also use to scroll through any clients you have entered using the record selector circled at the bottom of the frmClients.
Play around with the record selector to see how it works. In particular go past the last record and you will find you can enter new clients and access will automatically give them a ClientID. You can also cycle through your Clients and update them using this form it just isn't stylish. In the same way we can make a form for the groups table.
You make a form for the frmGroupSessions table in the same manner as the others but add a step. Replace the text boxes holding ClientID and GroupID with human readable comboboxes. Here is a link to help with that: https://www.google.com/search?q=access+change+text+box+to+combo+box&oq=access+change+text+&aqs=chrome.0.0i457j0l2j69i57j0j0i22i30l2.7503j0j1&sourceid=chrome&ie=UTF-8#kpvalbx=_r0sFYJ7vBcfY5gLz2aTgBw15
Becomes:
At this point play around to learn. Use the Record Selector at the bottom of frmGroupSessions to add and modify data. Play with the Tables and see what happens. Start messing with the form properties in particular the default view. Soon you will have ideas about how the form could be better and you can start figuring out how to style them.

Can I generate multiple new records based on value in another table, in MS Access 2013?

I'll qualify this with the upfront admission that I am not a professional programmer or database designer. I had a specific problem to solve - the need to manage a great deal of information on employee benefit requests - and limited resources, and built a database to replace the Excel spreadsheet I inherited. I'm learning as I go, and what I'd really like to find out is, can Access do what I'm envisioning, or do I need to adjust my goal?
The main tables my database includes are EMPLOYEES, REQUESTS, TASKS, and ACTIVITY (plus some auxiliary tables used for drop-down fields, etc.). Each employee can have multiple requests, and for each request, I used TASKS to keep track of all that needs to be done, by whom and by when, to see the request through from start to finish (I'm the only user of the dbase file itself, but I publish the task list as a report to those involved). ACTIVITY, as you would expect, is the "journaling" feature where I keep track of what's been done, conversations, etc.
What I want to do now is speed up the process of task entry, since for MOST requests, the taskflow is pretty similar. I already created tables for "TASK OWNER" and "TASK CATEGORIES" - both related to my primary TASKS table - so I could standardize the data entry for those fields, in addition to filtering on it ("show me everything the employee owns"). TASKS has a "NOTES" field so I can individualize the entry without changing the drop-downs. It's progress, but I'm still spending too much time adding the same however-many tasks to each new request I set up.
What I've been playing with in my head is identifying tasks with some sort of code that associates them with a type of request - i.e., an employee request for tuition reimbursement is identified as "request type 001" and all the tasks that normally go with a tuition reimbursement have a lookup field connecting them back to "001" - so that when I check a box or select "001 - Tuition Reimbursement" from a drop-down on my form, the 6 or 8 "standard" tasks automatically drop in to the TASKS subform, BUT they're NEW records - not just "template tasks" that I'm querying from my TASK CATEGORIES. I want to be able to tweak, edit, update, and even delete them, without affecting any other request.
I've found a lot of information adding new records via APPEND queries, but it seems to be limited to generating ONE record for each "transaction" if that makes sense - each time the query finds its value and performs the action, one record is generated. How do I get Access to recognize one value - request type - and generate each of the tasks associated with that request type as a new record in TASKS?
User selects category of request, such as 'Tuition Reimbursement' from a multi-column combobox. Hidden column of combobox has the category code and this is the bound column so this is value of combobox. Then code to save multiple records would be like:
CurrentDb.Execute "INSERT INTO Tasks(RequestID, TaskDesc) SELECT " & _
Me.tbxReqID & " AS RID, TaskDesc FROM TasksCategories WHERE TaskCat = " & Me.cbxCategory
The real trick is figuring out what event to put this code into. Should it be automatic after some data element is entered or should it be a button click? Then there is need to prevent duplicate entries - what if user accidentally clicks that button again? (This might be handled by a compound index setting in table.) Also, the new master record created on requests form has to be committed to table first. Record is committed when closing table/query/form, moving to another record, or running command to save.
As shown, your requirement is certainly possible, just keep in mind "the more user-friendly, the more code".
Now, when you develop code with specific issue, post it for analysis.

How to edit an existing record and not create a new one when using subforms in Access?

I have an access database that holds medical information. It holds quite a bit of information so i have grouped like fields together into individual tables and linked them using a common primary key. I have created a tab style form with subforms on each tab.
Some of these subforms contain fields from only one table, however there are a few subforms where i have included fields from more than one table.
For example, i have a table that holds blood transfusion data and a table that holds patient characteristics. Some Fields from the blood transfusion table and patient characteristics table are in the same subform, but I also have fields from both these tables in other subforms.
When i try to insert data into the sub-forms with fields from multiple tables i get the following errors..
update or cancelupdate without addnew or edit
and
The changes you requested to the table were not successful because
they would create duplicate values in the index, primary key or
relationship. Change the data in the field or fields that contain
duplicate data, remove the index, or redefine the index to permit
duplicate entries and try again.
From researching the problem i gather this is because access is trying to create a new record for both tables, but if a record has already been created with that primary key (from inserting data into a previous subform) it won't edit the existing record.
Does anyone know how to get access to edit the existing record in this instance instead of trying to add a new record? I have basic skills in VBA but this is a bit past my level of experience.
Any suggestions would be greatly appreciated.
I used have a whole long response about split forms instead but I was having a horrible time getting it to work. So here is my new and improved answer for using subforms.
Here is a link with sub form info if you want to brush up for your purposes https://support.office.com/en-us/article/Create-a-form-that-contains-a-subform-a-one-to-many-form-ddf3822f-8aba-49cb-831a-1e74d6f5f06b
Step 1
Make sure your main form is bound to the right table.
For my purposes I used a single combo box on my main form to search with. Make sure all the field parameters on your combo box are correct. This includes making sure the Row Source is correct and that you DO NOT have a control source entered.
Step 2
Don't press enter after making a selection in the combo box. To prevent people from hitting enter I created a dummy button at the bottom that says "Save and Refresh" but all it does it create a message window that pops up with "Save Successful". I find hitting enter creates the first error you keep getting. I'm not sure how to address this in a more sophisticated way yet.
Anything else that comes up I will add later.

Suggestion and auto-complete in form with one-to-many relationship in Access

I am trying to make a form for a very typical scenario: a customer makes an order. The customer might be new or returning. I have created an Access database with two tables: Job and Customer (linked by the primary key 'customer no'). The form I wish to create looks like this:
The customer table data is highlighted.
When the customer's name is beginning to be typed in, I want to see an updating list suggesting possible customer matches. If the customer happens to be returning, I can click on one of the drop-down options and have all other customer fields auto-complete.
What is the best way to create such a form?
I tried to achieve this using a comboBox and some code. However, if I use this method, the comboBox does not allow me to enter a customer name which isn't already in the customer's table. So I can't enter new customer details.
Ideally, this auto-complete/suggestion should work for all customer fields, such as phone number (in case the phone number is the only know customer info).
You could use a combobox which has LimitToList set to false, allowing entry of data not already defined in the combobox's rowsource; With this approach you would define a not-in-list event handler for the combobox to open a popup form for adding a new customer, ideally pre-initialised with the customer name just entered, and when data is saved in that form, control returns to this form, requeries the combobox (as it's contained data is now out of date), re-locks the customer just added, and fires it's after update event to display all the relevant customer-related fields appearing on this form.
However whether this is appropriate or not depends to some extent on the quantity of data that you have. If you've more than say 10000 customers in the database, I'd recommend instead having an elipsis (...) button beside customer name which opens a popup search screen, and provides whatever search options seem best (name, number, city, etc) for the entity being searched, a textbox, and find + add buttons; With huge data quantities you might also want to provide a means to prevent searching for matches (especially by multiple users across a busy network) where there is less than say 4 characters in the textbox, to improve performance.
You'd then use the text_changed event on the textbox to retrieve the data in the database which starts with the text currently existing in the textbox, and display this in a datasheet; The user can then either click Find or double-click the datasheet to select a customer which you then return to the calling form, probably by either a call to a public sub, or setting a tag value on that form - or click Add to add a new customer and invoke logic similar to the above.