Ms access : calculated field from other table - ms-access

I've been searching for this for a while and I can't seem to find anything!
Here's my problem:
I have a ms access database for the maintenance of the trucks of a company.
I've built a form in which you can see a VEHICLE and the amount of money spent on it. This information is available by a subform that takes information in the MAINTENANCE table
I would like to have the same exact information in the VEHICLE table so I could build charts (histograms)
basically I want a calculated field in my VEHICLE table that reads the MAINTENANCE table and sums up every maintenance for this vehicle.
I hope this is not impossible.

Its not impossible. However, you may need to rethink how you want to do this.
You could do this in C# or VBA, etc, but since I'm not an expert at those, I'll give you a simple solution.
Create the maintenace_total field in your vehicle table.
Create a new table (tbl_VehicleMaintenanceAmt) that only contains the fields for your unique vehicle identifier and maintenance total.
Create a new query (qry_AppendVehicleMaintenanceAmt) based on your maintenance table that groups by vehicle unique identifier and sums the maintenance amounts.
Change your new query (qry_AppendVehicleMaintenanceAmt) to append to your new table (tbl_VehicleMaintenanceAmt). This will give you a clean one row per vehicle with maintenance total.
Create a new update query that links your new table (tbl_VehicleMaintenanceAmt) with your Vehicle table by vehicle identifier, and update the maintenance_total in your Vehicle table with the Maintenance amount from tbl_VehicleMaintenanceAmt.
You'd want to clear out the tbl_VehicleMaintenanceAmt and re-append your maintenance total data to it every time you want to get accurate numbers.
You could also do this with Form and Subform grouping with Sums and Totals, but the explanation is a pain so I went as far as I'm willing. :)

Related

Multi-Table Query Not Updateable in MS Access

First post for me so please bear with me if I'm short on providing enough info.
I'm trying to put a query together that will be used as a subform on a project expense data entry form. As part of the query I want Access to pull the correct tax rates to calculate PST & GST correctly in calculated fields within the query. I have a query that consists of 5 tables:
tblProjectExpenseLineItems (PK: ExpenseLineItemID, FK: ProjectExpenseID)
tblProjectExpenses (PK: ProjectExpenseID, FK: ProjectNoID)
tblProjects (PK: ProjectNoID, FK: ClientID)
tblClientList (PK: Client ID)
tblTaxRate
Query design looks like this: qryProjectExpensesLineItemsExtended Query Design
The picture doesn't show it but the PSTTaxRate field is set to [tblTaxRate]![TaxRate] and the PST field is just the PST calculation on the expense line item.
I manually joined [tblClientList].[Province] to [tblTaxRate].[TaxJurisdiction]. These aren't related in the database relationships since neither fields are primary keys and I get the "indeterminate" relationship type. I have checked and confirmed that the values in these fields are in fact the same so results do show when I run the query.
The query fields are primarily from the tblProjectsExpensesLineItems table only since this is the table I want to update through the subform (I've tried adding the different PKs to see if that would change anything but no such luck). The only reason I have the other four tables is to get the [tblClientList].[Province] field so that I can pick up the location of the client and know which tax to charge. Where I live we've had our PST change a few times recently so I further filter the query using the [ExpenseDate] field to find the tax rate that fits between the [tblTaxRate].[StartDate] and [tblTaxRate].[EndDate] fields.
Things I've checked/read into:
I've checked that the table relationships have been set, are related to primary keys, and have "Enforce Referential Integrity" checked.
I've tried deleting tblTaxRate out of the query since it doesn't have an actual relationship. The query still isn't updateable and Access prompts me for the TaxRate, StartDate and EndDate fields when I run the query
I found a very detailed post here Why is my query not updateable? about reasons why queries aren't updateable. I'm pretty new to Access so I was able to rule out most of them, but some of them I don't quite understand (maybe something to do with the one-to-many and many-to-one relationships?)
Deleting all the tables except for the one I want to update. This of course makes the query updateable but Access prompts me for all the fields related to trying to find the tax rate.
I thought maybe an easy way out is to just manually enter tax rates but the database is being used for invoicing so I'm trying to eliminate potential for user input error.
I also thought this would be easier if I used form controls to do the heavy lifting but the tax calcs show up in many forms so I was hoping to keep the calcs at the query level so that I don't have to keep writing the calcs for every form and instead just reference the same query.
I'm at a total loss. I have the query responding properly but I can't do any data entry which is the sole purpose of the query! Any help is much appreciated!!
Scott

Organizing monthly account extracts for personal use MS Access

I'm a bit of a newbie with databases and database design, but I'm hoping someone can point me in the right direction. I currently have 14 monthly loan extracts, each of which contain all accounts, their status, balance and customer contact info as-of month end. Not knowing what to do, I imported each of the monthly files into Access with each table acting more like a tab from an Excel workbook. Laugh away - I now know that's not how it's supposed to work.
I've done my homework and I understand how to split up part of my data into Customer and Account tables, but what do I do with the account balances? My thought is to create a Balances table, create a relationship to the Accounts table and create columns for each month. This seems logical, but is it the best way?
99% of my analysis involves trend reporting and other ad hoc tasks - tracking the total balances by product type over time given other criteria, such as credit score or age. My intended use is to create queries to select the data I need and connect to it via Get & Transform in Excel for final manipulation and report writing.
This also begs the question "how normalized should my new database be?" Each monthly extract is cumulative, so a good 75% of my data is redundant contact info already, but how normalized should I go?
Sorry for ranting,but if anyone has any experience in setting up their own historical database or could point me in a direction that will get me on track, I would appreciate it.
Best practice for transactional systems is close to what you expect:
1. Create a Customer table
2. Create an Account table
3. Create an Account Balance table
4. Create relationships from the Account to Customer, and from the Account Balance to the Account table.
You can create a column for each month, provided you have Year as part of the key of the Account Balance table. Even better would be to have the key for the Account Balance be Account ID and Date.
However, since you are performing analytics over the data, a de-normalized approach is not only acceptable -- it is preferable. So yes, you can (and perhaps should, based upon your use cases) put all the data into one big flat table and then compile your analytics.

Need Help in Creating History Table in Access

In MS Access, i need to create a history table off a select query that is used for reporting? I don't want an append table as i need the select's data for reporting.
The answer that works best is you do want to use an append query.
Instead of garbaging up your database with lots of history tables, it's better to have one history table with a unique key to differentiate the multiple history reports.
Usually a "Time Stamp" field is a good primary key. Where each record in the report gets the same time stamp.
Also, you can have other key fields depending on the type of report it is. You may want a version field, or a re-try field. You also may want a final copy field. Having these fields will allow you to go back and delete garbage reports or updated reports or bad attempt reports.
Also having solid date fields will allow you to discriminate between daily reports, weekly reports, or monthly reports. (Let alone if you have to worry about Fiscal year, or retail calendars, etc.)
The good thing about having a single table is, you can always go back into your history table and pull out lots of historical data for other types of report comparisons... all in one query instead of trying to tie multiple tables together (mostly with hard to figure out names).
Do yourself and future programmers who will have to deal with your code a favor... and put all the history in one table. Especially since one of those future programmer may be you. You'll be thanking yourself.
Oh... and to get the data for the reporting, you use your primary key to pull out that data. Or... you can have a staging table for your report and then you append the staging table data to the History table (with all the proper key info).

Working out users points - update vs select

I have users who earn points by taking parts in various activities on the website and then the user can spend these points on whatever they like, the way I have it set up the at the minute is I have a table -
tbl_users_achievements and tbl_users_purchased_items
I have these two tables to track what the users have done and what they have bought (Obviously!)
But instead of having a column in my user tables called 'user_points', I have decided to display their points by doing a SELECT on all achievements and getting a sum of the points they have earnt, I am then doing another select on how many points they have spent.
I thought it might of been better to have a column to store their points and when they buy something and win stuff I do an UPDATE on the column for that user, but that seemed like multiple areas I have to manage, I have to insert a new row for the transaction and then update their column where if I use a query to work out their total won - spent I only have to insert the row and do no update. But the problem is then comes to performance of running and doing a calculation with the query.
So which solution would you go with and why?
Have a column to store their points and do an update
Use a query to work out the users points they can spend and have no column
Your current model is logically the right one - a key aspect for RDBMS normalization is not to repeat any information, and keeping an explicit "this customer has x points" column repeats data.
The benefits of this are obvious - you have less data manipulation code to write, and don't have to worry about what happens when you insert the transaction but can't update the users table.
The downsides are that you're running additional queries every time you show the customer profile; this can create a performance problem. The traditional response to that performance problem is to de-normalize, for instance by keeping a calculated total against the user table.
Only do that if that's absolutely, provably necessary.
myself, I would put the user points into a separate table PK'd by user ID or whatever and store them there and do updates to increment or decrement as achievements are attained or points spent.

Database Historization

We have a requirement in our application where we need to store references for later access.
Example: A user can commit an invoice at a time and all references(customer address, calculated amount of money, product descriptions) which this invoice contains and calculations should be stored over time.
We need to hold the references somehow but what if the e.g. the product name changes? So somehow we need to copy everything so its documented for later and not affected by changes in future. Even when products are deleted, they need to reviewed later when the invoice is stored.
What is the best practise here regarding database design? Even what is the most flexible approach e.g. when the user want to edit his invoice later and restore it from the db?
Thank you!
Here is one way to do it:
Essentially, we never modify or delete the existing data. We "modify" it by creating a new version. We "delete" it by setting the DELETED flag.
For example:
If product changes the price, we insert a new row into PRODUCT_VERSION while old orders are kept connected to the old PRODUCT_VERSION and the old price.
When buyer changes the address, we simply insert a new row in CUSTOMER_VERSION and link new orders to that, while keeping the old orders linked to the old version.
If product is deleted, we don't really delete it - we simply set the PRODUCT.DELETED flag, so all the orders historically made for that product stay in the database.
If customer is deleted (e.g. because (s)he requested to be unregistered), set the CUSTOMER.DELETED flag.
Caveats:
If product name needs to be unique, that can't be enforced declaratively in the model above. You'll either need to "promote" the NAME from PRODUCT_VERSION to PRODUCT, make it a key there and give-up ability to "evolve" product's name, or enforce uniqueness on only latest PRODUCT_VER (probably through triggers).
There is a potential problem with the customer's privacy. If a customer is deleted from the system, it may be desirable to physically remove its data from the database and just setting CUSTOMER.DELETED won't do that. If that's a concern, either blank-out the privacy-sensitive data in all the customer's versions, or alternatively disconnect existing orders from the real customer and reconnect them to a special "anonymous" customer, then physically delete all the customer versions.
This model uses a lot of identifying relationships. This leads to "fat" foreign keys and could be a bit of a storage problem since MySQL doesn't support leading-edge index compression (unlike, say, Oracle), but on the other hand InnoDB always clusters the data on PK and this clustering can be beneficial for performance. Also, JOINs are less necessary.
Equivalent model with non-identifying relationships and surrogate keys would look like this:
You could add a column in the product table indicating whether or not it is being sold. Then when the product is "deleted" you just set the flag so that it is no longer available as a new product, but you retain the data for future lookups.
To deal with name changes, you should be using ID's to refer to products rather than using the name directly.
You've opened up an eternal debate between the purist and practical approach.
From a normalization standpoint of your database, you "should" keep all the relevant data. In other words, say a product name changes, save the date of the change so that you could go back in time and rebuild your invoice with that product name, and all other data as it existed that day.
A "de"normalized approach is to view that invoice as a "moment in time", recording in the relevant tables data as it actually was that day. This approach lets you pull up that invoice without any dependancies at all, but you could never recreate that invoice from scratch.
The problem you're facing is, as I'm sure you know, a result of Database Normalization. One of the approaches to resolve this can be taken from Business Intelligence techniques - archiving the data ina de-normalized state in a Data Warehouse.
Normalized data:
Orders table
OrderId
CustomerId
Customers Table
CustomerId
Firstname
etc
Items table
ItemId
Itemname
ItemPrice
OrderDetails Table
ItemDetailId
OrderId
ItemId
ItemQty
etc
When queried and stored de-normalized, the data warehouse table looks like
OrderId
CustomerId
CustomerName
CustomerAddress
(other Customer Fields)
ItemDetailId
ItemId
ItemName
ItemPrice
(Other OrderDetail and Item Fields)
Typically, there is either some sort of scheduled job that pulls data from the normalized datas into the Data Warehouse on a scheduled basis, OR if your design allows, it could be done when an order reaches a certain status. (Such as shipped) It could be that the records are stored at each change of status (with a field called OrderStatus tacking the current status), so the fully de-normalized data is available for each step of the oprder/fulfillment process. When and how to archive the data into the warehouse will vary based on your needs.
There is a lot of overhead involved in the above, but the other common approach I'm aware of carries even MORE overhead.
The other approach would be to make the tables read-only. If a customer wants to change their address, you don't edit their existing address, you insert a new record.
So if my address is AddressId 12 when I first order on your site in Jamnuary, then I move on July 4, I get a new AddressId tied to my account. (Say AddressId 123123 because your site is very successful and has attracted a ton of customers.)
Orders I palced before July 4 would have AddressId 12 associated with them, and orders placed on or after July 4 have AddressId 123123.
Repeat that pattern with every table that needs to retain historical data.
I do have a third approach, but searching it is difficult. I use this in one app only, and it actually works out pretty well in this single instance, which had some pretty specific business needs for reconstructing the data exactly as it was at a specific point in time. I wouldn't use it unless I had similar business needs.
At a specific status, serialize the data into an Xml document, or some other document you can use to reconstruct the data. This allows you to save the data as it was at the time it was serialized, retaining original table structure and relaitons.
When you have time-sensitive data, you use things like the product and Customer tables as lookup tables and store the information directly in your Orders/orderdetails tables.
So the order table might contain the customer name and address, the details woudl contain all relevant information about the produtct including especially price(you never want to rely on the product table for price information beyond the intial lookup at teh time of the order).
This is NOT denormalizing, the data changes over time but you need the historical value, so you must store it at the time the record is created or you will lose data intergrity. You don't want your financial reports to suddenly indicate you sold 30% more last year because you have price updates. That's not what you sold.