Display many to many relationship in continuous form - ms-access

I can't figure out how to display a column that has many value for the same record in a continuous form
I got 3 tables
SalesCall
SalesCallId | etc..
Mill
MillId | name...
SalesCallMills <------ Junction table
Id | SalesCallId | MillID
the basic design for a many to many relationship.
When it's a simple form, I'm used to do a list and change the control source for the current ID with a SQL query.
What's the common practice to display this in a continuous form?
This was the form before when only 1 mill was possible.
I thought I could concat the mills, but it will be hard to read and it will be way to long.
So I thought about a list but I don't think it's possible to change the control source for each record.
Also, good to mention that this is read-only. It's not for adding or editing. The form to enter data is already made. And I think that one mill per record is not an option cause it would really confuse the user.
What's the proper way to display a multi value column with my database design?

This is a form with correlated subforms.
The two forms are synchronized via the link child and master fields:
Link Master Fields: Forms!Form7![SalesCall Subform].Form.SaleID
Link Child Fields: SalesCallId
And a little code in the Current Event of subform #1
Private Sub Form_Current()
Me.Parent.[SalesCallMills subform].Form.Requery
End Sub
Selecting a line in subform #1 displays the relevant detail lines in subform #2.
It should not be difficult to add suitable information on such things as mill name to the general outline.

The Junction Table will be the mainstay of your select, and you will hang the other tables from it.
You can use the Query Editor to view it visually, but the SQL statement would look like:
SELECT *
FROM (SalesCallMills
INNER JOIN SalesCall
ON SalesCallMills.ID=SalesCall.SalesCallID)
INNER JOIN Mill
ON SalesCallMills.ID=Mill.MillID;
(Access likes brackets around multi-table joins, so while they are not necessary for a pure SQL statement, Access will not work properly without them)
To view all the Mills against each SalesCall in a single line, you will have to leave the simple query behind, and write your own (vba) function
http://allenbrowne.com/func-concat.html has an example, and the code that will allow you to set the Mills field on your current form to something like =ConcatRelated("name", "Mill", "MillID= " & SalesCallMills.ID)

You could List the mills in a a text box by setting the format to rich text and then putting all the mills into the same field separated by the <br> tag like this.
Mill1<br> mill2<br>mill3
Considerations
1. This will mean that the text box has to be long enough.
2. You will have to concatenate the mills into a single field in you query which may not be feasible.

in a classic in traditional sense, there’s really not such a thing as a many to many relationship between two tables, however by cobbling together related tables one after another, you do at the end of the day due in effect get the same result of a many to many relationship, but technically that’s not what occurring between two tables. In effect you are always working your way down from a parent table to a child table. Those thinking in terms of junction tables are in fact thinking the wrong way.
If a person is allowed to have many favorite colors, then it in poor taste to call that table that simply links their many choices of color to the available colors as a "junction" table. It is far better to simply state that we need a table called:
My List Of Favorite colors table.
The fact the above table may then link to additional tables is moot. In fact it might have more than one column that are foreign keys, and then it not really a simple junction table, but at the day it is doing the same thing.
Anyway, in Access you can most certainly display two continues forms to display data modeled in this manner.
Let’s assume that each weekend we have to take in a bunch of donations from people. This means we have one main table with information about the date and time etc. of this donation event. Our next table would have people and their donation amount. The next table after that would be to take a donation amount, and split up their funds into different accounts. This is a classic accounting distribution problem that just about every accounting package from QuickBooks to whenever has to implement. As it turns out, this classic distribution problem can be solved with very little code when using access.
The trick to modeling these types of forms is to use several sub forms placed into one main form.
The following form shows this:
If you look at the top there’s a main record with information about this batch run and date and time. Now, on the left side is many people and a donation amount. And on the right side is that donation for the one person split out to many different accounts. So I’m displaying many people, and I’m also to display the many accounts that a donation may be split out to .
Keep in mind that access does not let you place a continuous subform inside of a continuous subform. However, you can certainly place two continuous of forms beside each other as the above screen shot shows to model the same affect that you desire.
There’s also surprisingly as mentioned very little code to manage this whole thing.
For the left side continuous form, because the link master and child settings are set to the main form record, then NO code is required for this form to be populated with data. However, for the right side continues form to follow and display the correct Accounting Data for each person in the leftr side continuous form, access will not automatically do this for you . However, a simple bit of code in the on-current event of the left side form will forced access to wake up and note the right side continues form has to be RE populated to display the donation accounts for that one particular person .
The one line of code placed in the left side on-current event will fix this:
me.Parent.Child2.Requery
The link master/child settings on the right side continuous form I use:
linkChildFields main_id (whatever is the name of the field in
this sub-form that is used to relate back to the parent table)
LinkMasterFields [MasterFormLeftSide].[form].[ID] ("masterFormleft" is the name of
the subform contorl you used to hold the continuous form on the left side ).
So, you’ll need a tiny little bit of code, but not a whole heck of a lot, and you now have a screen that displays many information related to many information.

I strongly disagree with "Those thinking in terms of junction tables are in fact thinking the wrong way." in #Albert D. Kallal's answer.
It is true that m:n relationships can't be implemented directly in a relational DB. That is why the one and only sane design of:
+----------+ +---------+
| Patients |--- m:n ---| Doctors |
+----------+ +---------+
... is:
+----------+ +-----------------+ +---------+
| Patients |--- 1:n ---| PatientsDoctors |--- n:1 ---| Doctors |
+----------+ +-----------------+ +---------+
Everything else might work in one way or another but is poor man's relational DB design. And with making compromises at the model design, at the very beginning of a project, the worse is very likely yet to come.

Related

Access changes table Relationships by itself

I am struggling with an issue in designing my Access database.
I am a caregiver, and part of my job is taking clients out into the community. I am attempting to build a catalog of outings to help the employees at our company come up with and store ideas for these. I want to store information for each of up to 5 types of events that clients can do at a location. That information includes the event type, when it runs and doesn't, and how much it'll cost, all of which would be user-selectable. (Separately in the same table, I want to include contact information and information that helps the user search for event locations, such as the ZIP code.) I have attempted to normalize the database by spreading event information across fields in the main table, linked to lookup tables. I am aware that Access has a limit of 32 relationships per table.
To help staff find event types, I am trying to set up a method for categorizing them. That requires setting up nested lookup tables, as shown in the first picture.
If I understand correctly, the additional "copies" of those lookup tables are aliases. When I save the setup for the relationships between those aliased lookup tables, close the Relationships window, and open it again, I find Access has changed them, as shown in the second picture. This happens whether I delete the lookup table information for each field in Datasheet View. I don't understand why it does this or how to fix it.
To answer your question:
In the object browser I see that you have only one table: t_OutingType. Therefore, the "tables" t_OutingType_2, t_OutingType_3 are just aliases; "pointers" to the same table (like a shortcut to a document). When you save the relationships and close the window, the relationship information is written to the metadata of the database. When you re-open the Relationships window Access re-builds the relationship diagram from the metadata, and it does not include the redundant aliases.
Additional advice:
Whenever you find yourself duplicating columns in a table, e.g., Event_1, Event_2, ... a little voice in your head should start shouting "Are you sure that's a good idea?" Imagine if you want to search the database for events that fall on a certain date. With the table layout described above you would need to ...
SELECT ... WHERE EventDate_1 = [theDate] OR EventDate_2 = [theDate] OR EventDate_3 = [theDate] ...
It's almost always better to split the Event information into a separate child table and maintain an association table between the child table and its parent.

Access: How to implement joining a contact to a trip?

(Table Relationships)
I'm developing a travel agency database, and I've got a table for contacts (people), a table for trips, and a junction table, people_has_trips. "Trip" refers to a table whose identity is mostly many-to-many relationships with various optional travel elements such as hotel, flight, etc. (I have doubts about this structure, but that's an issue for another question).
Anyway, I'm in the early phases of designing the form for Trips, which will almost entirely consist of subforms linking to junction tables. The problem that's given me the most difficulty so far is that of how to add a contact to a trip. I'm fairly new to access, and thus far I've been populating such tables using autofilling comboboxes, but the contacts table contains over 100,000 records, and as such some sort of search function would be prudent.
Here's what I have so far. This subform is based on the people_has_trips table, and currently is limited to showing existing records. I disabled all fields as not to allow the editing of People records, but I'm somewhat stumped as to how to handle adding more people. In my limited Access knowledge, the most logical solution to me seemed to be having a button to open a form that would allow the searching of People and perhaps the addition of new people.
Now, I have a fully realized form for entering new People (shown below), but it doesn't have any real search functionality besides Access's built-in filters. So my subform currently opens People and... does nothing else. Quite frankly, I have no idea where to go from here. Do I develop a second form for searching people, or do I build in search functionality to the primary People form, something I should probably do anyway? If so, How? And after doing either of those things, how do I then populate people_has_trips? The only answer I can think of involves the user clicking the button to open People, finding the person they want to add, and then manually entering the primary key into the subform, which surely isn't optimal.
The aforementioned People entry form
The solution, I would wager, is VBA commands. I've recently taken the time to learn some VBA, and I'm a bit more comfortable with it, but I just don't know where to begin with this problem. I'm confident that I can adapt and apply other people's VBA ideas and code, but I can't find a thread on this particular issue from which to do that! I'm guessing the reason I can't find any help for this issue is that it's so blatantly obvious that nobody has asked the question yet, or my Google skills are lacking. Either way, I'd be quite happy to facepalm in realization of the solution. Thanks any and all for their help!
You need to be focused on your core problem and as far as I understood, you want to search and add "users/contacts" to your "People on this trip" form.
Yes combo-boxes can eat up time loading 100k rows and it's not really search friendly.
In your "People in this trip" form you can:
have a text box => for search
have a combo-box => showing search result
[Search] [Add] [Clear] buttons
In theory,
search button performs a search on your TContacts table and assigns the results to the combobox. something like SELECT PersonId, FirstName, LastName From Prople WHERE firstName like #keyword OR lastNAme like #keyword ... other fields
User selects a specific result form the combo-box.
Add button then performs SQL operation adding selected user to your junction table and refresh your junction table.
something like: INSERT INTO people_has_trips (people_personId, trips_tripId) values (#selectedPersonId, #tripId); followed by requery
This is just a theory, you need to try out something and narrow it down to a specific problem. Otherwise your question might be marked as too broad.

How to eliminate database table row duplication

I have a question on databases and how information is displayed in regards to Primary and Foreign keys.
For example, there are three tables; Employees, Employee_tickets and Employee_comments.
Each employeecan have multiple tickets and also multiple comments. A foreign key is placed in the Employee tickets and Employee Comments table. My application is built in vb.net with Visual Studio and it is a desktop application. How can I query say.. Employee Name ('Jon Doe') and display all of his tickets in a grid as well as all of the comments people have made on him over time? I have created a View on the sql database which returns all of the information I require but for each ticket listed under ('Jon Doe') the View displays and Employee Name for every single ticket. Is there a way to display the employee name only once and then every ticket listed under that particular individual without displaying the Employee Name again or do I have to make Separate windows to segregate all of this?
This seems like a really dumb question and I cannot for the life of me figure out how to correctly display what is required in this situation.
Here is an example of what I am trying to explain:
So for troy there is one employee name entered in the Employee Names table, There is one CWB ticket entered in the CWB table but there are TWO PQ Cards entered in the PQR Ticket table. How Can I Display only one row for Troy and one Row for his CWB because there are only one of each entered in the tables then the two rows for the PQR Cards under his name?
I have created a view which gathers this information all into the one single view itself then bound the datagridview's to this View.
Your problem has nothing to do with databases. Rather, the issue is that you have an entity (the employee) that has two separate collections associated with it (tickets and comments) and you want to show the contents of both collections.
Doing this in a datagrid is difficult because in its simplest incarnation it's intended to show one collection of like items.
I can think of a number of possibilities:
In your code, convert each collection to a single string value and display that single string value on the row with the employee's name. This conversion could be to comma-separate a stringified version of each item in the collection (as suggested by BS123 in the comments) or could simply be a summary (eg "5 Tickets").
Put the basic employee information in one data grid and then have two additional data grids below it, one bound to the Tickets collection and one to the Comments collection.
Embed data grids directly in the main data grid, one in the Tickets column and one in the Comments column, and bind each one to the appropriate collection in the employee.
Your database structure is correct so don't change that, you simply need to solve the issue of presentation.
What you're missing here is a controller between your view and your model. Your view is presenting exactly what it was given to present - it's up to you to format it.
There are several possible solutions to this, and the correct one partially depends on needs and infrastructure.
If you infrastructure is solid and your needs are near real time, consider dropping separately querying to fill your second and third tables based on what is picked in the first. This will increase the load on the database, but your data will almost always be correct, and the data will come from the database the way you want to see it.
If the database-centered solution is not good for you, LINQ provides some good ways to filter your data into typed collections that would present exactly what you want the user to see.
To get the users:
Dim users = From l In data.lines
Group By FirstName = l.firstName, LastName = l.lastName
Into Tickets = Group, Count()
You can then present this object to your grid. While dynamic typing works here, I think it would be easier to manage view interactions with defined classes. I'll leave that part up to you. Do some searching on LINQ to fill in the rest of the blanks. It's pretty neat stuff.

MS Access sub-sub forms

I am using MS Access as a front end for a MySQL database. In it I have several tables, all based around the concept of a Household and People (one to many, respectively). From that there are several join tables (such as Ethnicity and Dietary Restrictions) which are many to many. I would like to be able to edit this from a single form in MS Access.
So far I have it set up so that I can edit the household information, view/edit all the people associated with it, and expand the person detail to view 1 (out of 3) of the join tables associated with that person record. I cannot figure out how to get all 3 tables to be visible, does anyone know how to do this?
I would built 3 grids using continues forms, or 3 forms in data sheet view.
You then create a 4 form, and drop in the above 3 forms.
In the master form (which is now a subform), in the on current event, you
place the following command to make the child forms follow this form.
me.Parent.Child1.Requery
me.Parent.Child2.Requery.
In the link child/master settings for child 1, you place:
linkChildFields main_id (whatever is the name of the field in
this sub-form that is used to relate back to the parent table)
LinkMasterFields [MasterForm].[form].[ID]
In the link child/master settings for child 2 form you place
linkChildFields main_id (whatever is the name of the field in
this sub-form that is used to relate back to the parent table)
LinkMasterFields [MasterForm].[form].[ID] ("masterForm" is the name of
the contorl you used to hold the master form).
The "many" to many screen looks like this:
The above is a classic accounting or funds distribution in which we take an amount like $50 and distribute the amount over many accounts.
Sounds like a structure problem, actually. Wouldn't it be more efficient to base your property accessory tables (dietary restrictions, occupations, etc) - properties that a single person might possess a number of - on your personal information table, perhaps keyed to a individual ID of some sort (employers often use SSNs, as they are unique - though in your case, you might just make them auto-generating). Items like Ethnicity, and position within a household are something an individual possesses one of, and would be something you could indeed place within your personal information table.
With proper structuring, and the right query work - you can have a form that allows you to edit all of these properties on a family while keeping referential integrity.

Why would a Microsoft Access form create records for one query but not another?

I have an Access database. Let's pretend it's for a pet store.
There's a table for animals.
Animals (animal_id, birth_date, price)
And then specific tables for the different types of animals we sell.
Dogs (animal_id, bark_volume)
Cats (animal_id, collar_size, shedding_rate)
Fish (animal_id)
Fish aren't interesting so they don't have any special fields. The Fish table just exists so you know which records in the Animals table are fish.
Now, I have a general purpose form for adding animals to the pet store. Before you get the form, you first have to say what kind of animal you're adding. Based on that, the form shows/hides fields, changes its recordsource, and binds the fields to the appropriate data columns. The form pulls its data from the queries DogInfo, CatInfo, and FishInfo.
Now, when you enter a dog or a cat, everything is fine. A record is added to both Animals and either Dogs or Cats.
However, when you enter a Fish, all you get is an Animal, no Fish.
What could be causing this? Is it somehow caused by the lack of other columns on the Fish table?
(Let's leave aside the fact that updating tables with a select query makes no sense at all. I didn't expect Access to let me do it at all in the first place, but Access's motto seems to be "Make the wrong thing easy to do and the right thing awkward to do." The database is relatively simple and infrequently used, though, and it's at least 100 times better than it was before I started working on it, so I'm not really too worried about this issue as long as I can make it work.)
"Is it somehow caused by the lack of other columns on the Fish table?"
Yes - when you enter data on child records (Dogs and Cats) Access will automatically fill in the parent ID (animal_id)
Since there is no data entry for the fish record it does not get created. You have to do that in code. Not sure how your form and data source is setup but you would do something like this on one of the form events:
Fish![animal_id] = Animal![animal_id]
Edit
In your FishInfo query you must give the Fish.[animal_id] an alias - you can't have two fields with the same name - call it Fish_animal_id
Then in the Form_BeforeUpdate event put this:
Me.Fish_animal_id = Me.animal_id
Have you thought about configuring relationships on the different tables? Given the design above, I would start by adding an identifying column to the specific-animal tables, and setting it as the primary key. E.g.:
Dogs(DOG_ID, animal_id, bark_volume)
Cats(CAT_ID, animal_id, collar_size, shedding_rate)
etc. In the relationships view, you'd then define a one-to-many (one-to-one?) relationship from Animals.ANIMAL_ID to Dogs.animal_id. You could then hook up the Animals table to a combo/listbox control on your form to select a record from that table. I think if you configure the control correctly, you can even create new records from that control (or you could use a subform).
Do you not have an separate IDs for the Dogs/Cats/Fish tables? Assuming the only difference is the number of columns, I'd be curious if that suddenly fixed it.
Bad design aside, did you set up a relationship between the various tables? And did you set the tables to enforce referential integrity?