I have the following 3 tables:
Retailers - ID, Name
Registration - ID, Status (YES/NO)
Refund - ID (populated into a dropdown list from Retailers table), Name (Empty), Status (Empty)
Retailers is a table full of data, while Refund starts off as an empty table that gets filled in as a Refund Form is filled up. After creating a form based on the Refund table, how do I allow a user to select an ID from the dropdown list and populate the corresponding Name into the Name field and Status into the Status field?
What are the queries needed and how do I integrate this into the form?
I have tried the method found here - https://www.linkedin.com/pulse/autofill-form-microsoft-access-tim-miles
However, I have run into 2 problems:
1) The form does not appear in "Form View"; it is only viewable in layout view. I have read many links saying that the queries are read-only or that there are no records in the first place etc. The answers don't make sense.
2) If I bind the form (instead of a table) to a query this way, how do I save this new data into another table? My intention was to have the record saved in Refund table.
Sounds like Refund is your base table here. So, the query you want is:
SELECT a.[ID], b.[Name], c.[Status]
FROM Refund as a
Left Join Retailers as b
ON a.[ID] = b.[ID}
Left Join Registration as c
ON a.[ID] = c.[ID]
You'll need to make all 3 ID fields the Primary Keys in their respective tables. This should make the query updateable, and then you can use this query as the DatSource for your form.
You also have to make sure you set up the Relationships for all the tables. If you've never done it, it's easy to do and Microsoft gives you instructions here:
https://support.office.com/en-us/article/Create-a-relationship-40c998dd-4875-4da4-98c8-8ac8f109b85b
By setting up referential integrity in the relationships, you can save the data.
Related
I am looking for help with database design for a small project I am working on.
In short what I am trying to achieve is to have say the following tables:
Paddocks
Paddock ID
Paddock Name
Paddock Size
etc.
Cattle
Herd ID
Herd Name
Number of cows
Current Paddock
Cattle_Movements
Herd Name
Current Paddock
New Paddock
Date
etc.
I was hoping to have the 'Cattle_Movements' table be like a summary of all movements of a herd of cattle. And when a herd is moved from one paddock to another it would update the 'Current Paddock' field in the 'Cattle' table.
At this stage I am trying to workout the relationships, queries and high level process that I will need to implement.
Any help will be greatly appreciated.
Start by setting up a normalized table structure. make the tables below and hook them together with the relationships tool on the ribbon under database tools-relationships. To create a relationship drag the primary key from one table to the corresponding and same named foreign key in the table that will be the many side of the relationship. In the pop up make sure to check the enforce referential integrity, cascade update, and cascade delete checkboxes.
I've highlighted the two "Many to Many Relationships" in this normalization. HerdsPaddocks is a more generic name for the CattleMovements Table. There are other possible normalized table structures, but the subtle differences are beyond the scope of this answer. When you are ready, look up table normalization and Many to Many Relationships.
Next, Close the Relationships tool, select a table from the sidebar and on the ribbon under Create hit create form. Do this for all the tables. Now we have a working database but you need to learn how to use it. So play!
Below I gave some play suggestions, but just play with everything until you figure out how to use the forms to (add, search, edit) cows, herds, and paddocks. Also learn why you should delete the primary keys from all the forms and how to replace the foreign keys like CattleType in the Cattle Table with the user friendly CattleTypeDesscription from the CattleTypes Table.
Start with the Herds table and enter some random herds. (pro tip: never add data to the table directly except when playing the error rate is too high). Then Open the herds form where you can browse and edit the herds.
Play tips: In the Table Herds HerdID is both an autonumber and a primary key. It behaves differently from the other columns. Check it out. after that delete the HerdID textbox from the form and see what happens(a good thing). How do you add herds using the Herds Form?
Moving on to playing with the Cattle form, first make sure to add a few CattleTypes to the CattleTypes table. Then at some point, try replacing the CattleTypeID in the Cattle Form with the CattleTypeDescription: https://btabdevelopment.com/how-to-change-a-text-box-to-a-combo-box-wont-work-with-data-access-page/
Also, note the Cattle Form has a subform allowing you to simultaneously assign/edit cattle assignments to herds.
Once you are comfortable adding and editing data, play with the query editor. For instance, to get how many cows are currently in Paddock holds10cattle (my dummy data).
query 1 showing the relevant data
results from query1:
Query 2 getting really close:
Query 3: which gives the number 2:
'Query 3 SQL from SQL pane of query designer
SELECT Count(Cattle.CowName) AS CountOfCowName
FROM Paddocks INNER JOIN ((Herds INNER JOIN (Cattle INNER JOIN CattleHerds ON Cattle.CattleID = CattleHerds.CattleID) ON Herds.HerdID = CattleHerds.HerdID) INNER JOIN HerdsPaddocks ON Herds.HerdID = HerdsPaddocks.HerdID) ON Paddocks.PaddockID = HerdsPaddocks.PaddockID
GROUP BY Herds.HerdName, Paddocks.PaddockName, HerdsPaddocks.HerdPaddockEndDate, HerdsPaddocks.HerdPaddockStartDate
HAVING (((Paddocks.PaddockName)="holds10cattle") AND ((HerdsPaddocks.HerdPaddockEndDate) Is Null) AND ((HerdsPaddocks.HerdPaddockStartDate)<Now()))
ORDER BY HerdsPaddocks.HerdPaddockStartDate;
Next Steps could include the specific paddock with a parameter and using the query in a report.
I have 4 tables.
Table1 (primary)
Id
Table2 (foreign 1)
Id
Table1Id
Table3 (foreign 2)
Id
Table1Id
Etc
Table1 could have a record without table2,3 and 4 as well.
Now we have many records added to these tables and our application fetches to construct a response based on IDs in Table1.
You would normally add records in Table1 first then table 2 and 3 etc..
Our problem is that our polling (runs every 30seconds) application picks Ids from table1 but fails to get its linked records from Table2,3 and 4 because the application tries to fetch before linked records get saved in table 2,3 and 4 after saving a record in table1.
Is there a way of preventing this? Can we save foreign key records first? This way, the application won't see a record in table1 untill all linked records get saved in table2 and 3? Is it a common and safe practice?
Any advice would be great!
Thank you in advance
Depending on your system design you could always have this race condition. For example in a web application if you have a page that allows you to add a TableA, save it, then click a button to enter a related TableB, there is a period of time where a query on TableAs would receive an incomplete representation.
The solution is to either design the system or the data in a way that it can always be counted on to indicate that the data is in a complete state. For example, instead of designing it so that page-by-page entities in the relationship are saved independently, the user is given the ability to create the entire object graph. Entity Framework works with navigation properties for managing relationships, so if the client-side process walks through capturing the data for a Table A, then related Table B, and C etc. then passing all of those details in a structure to be persisted, you can have a single "Save" operation that creates the associated entities all in one go with one call to SaveChanges. This ensures all entities are committed together, or not at all. (if there is an exception) EF can take care of ensuring the tables are populated in the right order and assigning the FKs where needed. You don't need to "save" a TableA to get it's ID to populate in the TableB:
var tableA = new TableA
{
Name = viewModel.Name,
TableB = new TableB
{
Name = viewModel.BsName,
// ... or use biewModel.BDetails.Name, etc.
},
TableC = new TableC
{
// ....
}
};
context.TableAs.Add(tableA);
context.SaveChanges(); // Saves the A, B, and related C, etc.
If the data is rather large and complex and it doesn't make sense to try and capture everything at once, for instance if the data might be entered over a significant span of time given the user has to accumulate or check data etc. before the record state is considered complete enough to be queried on, then you can consider using something like a Status on your top level table. (TableA) This could be something like an enumeration. When you create your TableA record initially, the status would be defaulted to something like "InProgress". Any query reporting or such looking at TableAs would know only to query records with a Status of "Complete". As the user enters their Table B, C, etc. there would be either an automatic validation or manual assertion to determine if the TableA record can be marked off as "Complete", updating the status. From that point the report/summary query views would start seeing that row in results.
I am currently working in a SQL server database where I have a table User that has a schema like so:
username
category
user1
gaming
user2
gaming
user3
sports
My summary table UserCategoryCount is a simple groupby statement for how many users belong to each category and looks like this:
category
numUsers
gaming
2
sports
1
New entries are constantly being uploaded to the User, and I want to be able to stream updates in the User table to the UserCategoryCount summary table. I am aware that I can create a simple VIEW statement that performs a groupby on the User table, but I would like UserCategoryCount to be its own table that automatically changes based on new users being uploaded to the User table.
My first thought was to create a trigger that will detect when the User table has been updated. So far, the most simple but cheesy solution I can think of is creating a trigger that simply deletes and refreshes UserCategoryCount:
CREATE TRIGGER TRG_Add_User
ON User
AS
BEGIN
DELETE FROM UserCategoryCount
INSERT INTO UserCategoryCount (category, numUsers)
SELECT Category, Count(Category) as numUsers
FROM User GROUP BY Category
END
GO
But this seems like a really hacky way of updating the UserCategoryCount table. Any help on how to improve this update statement so that I don't have to completely overwrite the table every time a new user or batch of users has been inserted would be greatly appreciated.
For a start, your trigger is seriously flawed: it does not use the inserted or deleted tables and instead recalculates the whole thing every time, this is going to be very bad for performance. It also does not specify whether it is for inserts, updates or deletes.
A much better solution is to use an indexed view. This is like a regular view, except that the server maintains the actual data on disk, and updates it in real-time whenever there are changes to the underlying tables.
CREATE OR ALTER VIEW dbo.UserCategoryCount
WITH SCHEMABINDING
AS
SELECT
u.Category,
COUNT_BIG(*) AS numUsers
FROM dbo.User u
GROUP BY u.Category;
GO
CREATE UNIQUE CLUSTERED INDEX CX_UserCategoryCount ON dbo.UserCategoryCount (Category);
There are some restrictions on indexed views, among them:
They must be schema-bound, and therefore underlying columns cannot be changed
All tables must be two-part, schema and table
Only joins allowed are INNER or CROSS, no LEFT/RIGHT/FULL/APPLY or derived tables, CTEs or subqueries.
If there is a GROUP BY, you must add COUNT_BIG, and the only other aggregate allowed is SUM
I am quite new to creating dbs in Access but I am not a fan of subforms, I can already tell that much, they are nice for one to many relationships (one customer, many orders) but when I just want to reduce redundancy and create a one to one relationship between tables and I only at all times would need one record from another table, subforms no longer feel so nice.
My example:
I have 2 tables, 1 for companies (ID, company name, country ID) and one for countries (country ID, name of the country). To eliminate repetition of country names I use country ID to link the 2 tables, and only add the ID of the country, not its name.
When I create a form for the "companies" table I want one field that says where that company is located instead of a subform (because I still havent figured out how to hide the box around it), so practically having one field that's connected to a different table.
And then through the one to one connection, when a record is selected the form would show in one field where the company is located. Is this possible?
Extra: I have 2 countries in my "country" table, the UK and Germany, but a new company I am adding a record from this form, is located in France, is it possible that I just enter France into the field and it automatically creates a new record in the "country" table for France, and also adds the new record's ID to the "company" table, to the company that's located in France
It seems your form and subform are based directly on tables. Try basing your main form on a query:
SELECT
company.ID,
company.CompanyName,
company.CountryID,
country.CountryName
FROM
company
INNER JOIN country ON
company.CountryID = country.CountryID
This will eliminate the need for a subform.
Extra: You may actually want to have the 'country creation' function on a separate form, or invoked from a button push on this main form.
Having Country IDs to force users to pick a standard country from a list is a very good idea. However if you also let them arbitrarily enter new ones in the same box you're trying to prevent them from mistyping in, that good work can come undone.
Yes this is absolutely possible. The way I do this is with unbound forms, so I control all of the SQL statements to tell the data what to do and where to go.
Since you have 3 fields being sent into a row in the "companies" table and 2 fields being sent into a row in the countries table with 1 of the fields being in a relationship (I'm assuming 1 to many), create 4 textboxes (or whatever other control) on your form. The controls will be for: ID (assuming this is inputted by the user and not an autonumber. If it is, please comment below), company name, country ID, name of country. When you fill all of them out, have a button with a Click event. In here you will have 2 SQL statements to insert records, 1 for each table.
The code will look like this:
Private Sub button_Click()
DoCmd.RunSQL "INSERT INTO companies VALUES ([ID].Value, [company name].Value, [country ID].Value)"
' The words in the [] are the names of your controls on the form
DoCmd.RunSQL "INSERT INTO country VALUES ([country ID].value, [country name].value)"
End Sub
I am using Oracle with Oracle Forms builder (Middleware) both 11gR2. I am creating a system for purchasing records. I have the following 2 tables.
(a) product (master) : prodid(PK), prodname ...... etc.
(b) purchase (detail) : prodid(FK), quantity, ...... etc.
My plan: All the product details will be in the product table. purchase table will be used only to input purchase information. This table can't input any new product. If any new name, that info will have to be input into product table first. This way I can reduce duplicate names.
Now I am having difficulties relating to prodname (name of the product) column in the form.
I created forms using the purchase table only. This table does not have the prodname (because I put this field in product table) column. But during data entry, they need to see the product name !
So I created text item (tabular, database - no). Then I created LOV, attached to text item, input the prodid in prodid field in the form. LOV part is fine.
I run the form. click the text item, LOV appears, select a name, click OK. product name, product id, etc. appears in their fields as it should be. LOV is working fine. Now I can only input data but having difficulties updating. I mean if I input a name (LOV) in the text item, press execute query, shows records from the database but names in the text item disappear. Since the name is not here, it's not comfortable to update.
I think LOV is not the good idea here. May be I need to use PL/SQL in a trigger somewhere.
But I could not figure it out. I searched google but no luck. Is there anyone who can give me any idea or some example code/trigger please.
Since the product name is an non-database item, when execute query runs, the field is cleared and since no column is assigned to that field, it doesn't repopulate.
The usual way to populate this field is to have a function which returns the product name based on the id that is pressed and call the funtion in POST-QUERY trigger.
Basically it's a pretty simple task but I was having difficulties due to the lack of my experience. However, what I have done is -
create the text item (name : product_name) in the canvas
set properties for the product_name (database : No, .... etc as needed).
Create a block level POST-QUERY trigger and write the PL/SQL block to populate the field. For example, I wrote the following.
BEGIN
SELECT prodname INTO :purchase.product_name
FROM product WHERE product.prodid = :purchase.prodid ;
END ;
That's it and when perform execute_query in the form, it will bring the product name from another table. - Query problem is solved.
Now create an LOV using product table to bring the product name and product id.
Associate this LOV to the product_name text item. So whenever you need to input information about a purchase, just use the LOV to populate the product name field. And then input the subsequent fields as well.
This way both of my issues (query and data entry) are resolved.
I did this according to the suggestions given by Sathya and a video (6 minutes) from the youtube at https://www.youtube.com/watch?v=0nqldnGt8KA.
Thanks to Sathya and youtube.