ACCESS - calculating prices - ms-access

I have one table in my access DB which contains a list of all devices that has been sold to our customer. We have only one customer and only one type of device. The table contains details like name, serial, warranty detail of device. Now we need to calculate the price for invoice purpose. The thing is that the price should be calculated depending on amount of sold devices and also we don't want to hard code the price instead we would like to use a separate table whit different category of prices and calculating the price based on this table, because of the prices changing frequently and so we should modify the price value only in one table.
We have 3 category of price : if customer bought 100 device then the unit price is 15$ else if 200 devices the unit price would be 10$ else if 300 then price for unit would be 5$. So based on these rules we will need to calculate the price.
So I'm looking for the right approach that would be for this problem.

This is a very open-ended question and is impossible to definitively answer without more information about the architecture of the database.
There are 3 different ways I usually perform a calculation inside my Access databases.
perform a calculation inside a query. For simple things.
perform a calculation inside a module function, that is called by a query. For complicated things.
perform a calculation inside a module vba subroutine, that is called by a button OnClick Event. For extremely complicated things.

You could do a cross join as long as you have a range wide enough to account for all possibilities (i.e. some ridiculous upper boundary like 9999999). Otherwise a subquery would work with the same WHERE clause:
SELECT Prices.Price
FROM Prices
WHERE (Prices.MinQuantity <= Invoice.Quantity) AND
(Prices.MaxQuantity >= Invoice.Quantity)
As Gustav and V-ball point out there are many ways to set this up depending on your needs.

Related

Using a MySQL View to Retrieve Running Total

We're building an e-commerce system and we need some help in deciding on what's the best way to determine how many stocks are available per product.
Say we have the tables "products", "products_in", and "products_out". "products_in" records all our transactions that increase the quantities of our products (e.g. when we buy the products from our wholesale suppliers). While "products_out" records all our transactions that decrease the quantities of our products (e.g. when our customers buy the products).
In our apps, retrieving the quantities available for our products is more common than writing/updating records in the "products_in" and "products_out" tables. Given this, will the use of a MySQL view that depends on "products_in" and "products_out" and computes the available stock be more efficient than computing it on the fly every time we query it? Will the value on the view be recomputed every time there's a new record in "products_in" or "products_out"? Or will the view recompute the value every time we query it (which can be quite expensive in our case)?
will the use of a MySQL view that depends on "products_in" and "products_out" and computes the available stock be more efficient than computing it on the fly every time we query it? Will the value on the view be recomputed every time there's a new record in "products_in" or "products_out"? Or will the view recompute the value every time we query it (which can be quite expensive in our case)?
Let's think of the db steps in each case:
Case 1 If you compute available_stock every time a product comes in or goes out and store it in say product table
If product comes in, Insert queries in product_in table or if product goes out, Insert queries in product_out table
In either case, Update queries in available_stock column of product. (Assume here if 10 products come or 10 products go, there will be 10 individual queries that will be fired) - Expensive?
Case 2 If you compute available_stock in view everytime and not store it in database
Fetch records from product_in and product_out tables (only for few products for which you want available_stock), do some math, and display the estimated stock - Expensive?
I personally would go with case 2, because it involves less db transactions overall then case 1 which involves tons of transactions to keep the stock in sync.
Footnote In the sidelines, I'd definitely say that if you are hardcore 'Object Oriented Programmer' then your db mappings definitely violates the fundamentals. Products_in, Products_out are both the same entities (objects) that records the inventory/stock transactions (like Father,Mother entities are Persons), therefore you should make them encapsulated into one general table ProductInOutData.
In ProductInOutData, you can then add an enum having either in value or out value. Having both in and out records in one table will not only improve the readability and accessibility but also will help in easy calculation of the products coming in or going out making the case 2 more lightweight.

How to store recent usage frequency in MySQL

I'm working on the Product Catalog module of an Invoicing application.
When the user creates a new invoice the product name field should be an autocomplete field which shows the most recently used products from the product catalog.
How can I store this "usage recency/frequency" in the database?
I'm thinking about adding a new field recency which would be increased by 1 every time the product was used, and decreased by 1/(count of all products), when an other product is used. Then use this recency field for ordering, but it doesn't seem to me the best solution.
Can you help me what is the best practice for this kind of problem?
Solution for the recency calculation:
Create a new column in the products table, named last_used_on for example. Its data type should be TIMESTAMP (the MySQL representation for the Unix-time).
Advantages:
Timestamps contains both date and time parts.
It makes possible VERY precise calculations and comparisons in regard
to dates and times.
It lets you format the saved values in the date-time format of your
choice.
You can convert from any date-time format into a timestamp.
In regard to your autocomplete fields, it allows you to filter
the products list as you wish. For example, to display all products
used since [date-time]. Or to fetch all products used between
[date-time-1] and [date-time-2]. Or get the products used only on Mondays, at 1:37:12 PM, in the last two years, two months and three
days (so flexible timestamps are).
Resources:
Unix-Time
The DATE, DATETIME, and TIMESTAMP Types
How should unix timestamps be stored in int columns?
How to convert human date to unix timestamp in Mysql?
Solution for the usage rate calculation:
Well, actually, you are not speaking about a frequency calculation, but about a rate - even though one can argue that frequency is a rate, too.
Frequency implies using the time as the reference unit and it's measured in Hertz (Hz = [1/second]). For example, let's say you want to query how many times a product was used in the last year.
A rate, on the other hand, is a comparison, a relation between two related units. Like for example the exchange rate USD/EUR - they are both currencies. If the comparison takes place between two terms of the same type, then the result is a number without measurement units: a percentage. Like: 50 apples / 273 apples = 0.1832 = 18.32%
That said, I suppose you tried to calculate the usage rate: the number of usages of a product in relation with the number of usages of all products. Like, for a product: usage rate of the product = 17 usages of the product / 112 total usages = 0.1517... = 15.17%. And in the autocomplete you'd want to display the products with a usage rate bigger than a given percentage (like 9% for example).
This is easy to implement. In the products table add a column usages of type int or bigint and simply increment its value each time a product is used. And then, when you want to fetch the most used products, just apply a filter like in this sql statement:
SELECT
id,
name,
(usages*100) / (SELECT sum(usages) as total_usages FROM products) as usage_rate
FROM products
GROUP BY id
HAVING usage_rate > 9
ORDER BY usage_rate DESC;
Here's a little study case:
In the end, recency, frequency and rate are three different things.
Good luck.
To allow for future flexibility, I'd suggest the following additional (*) table to store the entire history of product usage by all users:
Name: product_usage
Columns:
id - internal surrogate auto-incrementing primary key
product_id (int) - foreign key to product identifier
user_id (int) - foreign key to user identifier
timestamp (datetime) - date/time the product was used
This would allow the query to be fine tuned as necessary. E.g. you may decide to only order by past usage for the logged in user. Or perhaps total usage within a particular timeframe would be more relevant. Such a table may also have a dual purpose of auditing - e.g. to report on the most popular or unpopular products amongst all users.
(*) assuming something similar doesn't already exist in your database schema
Your problem is related to many other web-scale search applications, such as e.g. showing spell corrections, related searches, or "trending" topics. You recognized correctly that both recency and frequency are important criteria in determining "popular" suggestions. In practice, it is desirable to compromise between the two: Recency alone will suffer from random fluctuations; but you also don't want to use only frequency, since some products might have been purchased a lot in the past, but their popularity is declining (or they might have gone out of stock or replaced by successor models).
A very simple but effective implementation that is typically used in these scenarios is exponential smoothing. First of all, most of the time it suffices to update popularities at fixed intervals (say, once each day). Set a decay parameter α (say, .95) that tells you how much yesterday's orders count compared to today's. Similarly, orders from two days ago will be worth α*α~.9 times as today's, and so on. To estimate this parameter, note that the value decays to one half after log(.5)/log(α) days (about 14 days for α=.95).
The implementation only requires a single additional field per product,
orders_decayed. Then, all you have to do is to update this value each night with the total daily orders:
orders_decayed = α * orders_decayed + (1-α) * orders_today.
You can sort your applicable suggestions according to this value.
To have an individual user experience, you should not rely on a field in the product table, but rather on the history of the user.
The occurrences of the product in past invoices created by the user would be a good starting point. The advantage is that you don't need to add fields or tables for this functionality. You simply rely on data that is already present anyway.
Since it is an auto-complete field, maybe past usage is not really relevant. Display n search results as the user types. If you feel that results are better if you include recency in the calculation of the order, go with it.
Now, implementation may defer depending on how and when product should be displayed. Whether it has to be user specific usage frequency or application specific (overall). But, in both case, I would suggest to have a history table, which later you can use for other analysis.
You could design you history table with atleast below columns:
Id | ProductId | LastUsed (timestamp) | UserId
And, now you can create a view, which will query this table for specific time range (something like product frequency of last week, last month or last year) and will give you highest sold product for specific time range.
Same can be used for User's specific frequency by adding additional condition to filter by Userid.
I'm thinking about adding a new field recency which would be increased
by 1 every time the product was used, and decreased by 1/(count of all
products), when an other product is used. Then use this recency field
for ordering, but it doesn't seem to me the best solution.
Yes, it is not a good practice to add a column for this and update every time. Imagine, this product is most awaiting product and people love to buy it. Now, at a time, 1000 people or may be more requested for this product and for every request you are going to update same row, since to maintain the concurrency database has to lock that specific row and update for each request, which is definitely going to hit your database and application performance instead you can simply insert a new row.
The other possible solution is, you could use your existing invoice table as it will definitely have all product and user specific information and create a view to get frequently used product as I mentioned above.
Please note that, this is an another option to achieve what you are expecting. But, I would personally recommend to have history table instead.
The scenario
When the user creates a new invoice the product name field should be an autocomplete field which shows the most recently used products from the product catalogue.
your suggested solution
How can I store this "usage recency/frequency" in the database?
If it is a web application, don't store it in a Database in your server. Each user has different choices.
Store it in the user's browser as Cookie or Localstorage because it will improve the User Experience.
If you still want to store it in MySQL table,
Do the following
Create a column recency as said in question.
When each time the item used, increase the count by 1 as said in question.
Don't decrease it when other items get used.
To get the recent most used item,
query
SELECT * FROM table WHERE recence = (SELECT MAX(recence) FROM table);
Side note
Go for the database use only if you want to show the recent most used products without depending the user.
As you aren't certain on wich measure to choose, and it's rather user experience related problem, I advice you have a number of measures and provide a user an option to choose one he/she prefers. For example the set of available measures could include most popular product last week, last month, last 3 months, last year, overall total. For the sake of performance I'd prefer to store those statistics in a separate table which is refreshed by a scheduled job running every 3 hours for example.

Stock management database design

I'm creating an Intranet for my company, and we want to have a stock management in it. We sell and rent alarm systems, and we want to have a good overview of what product is still in our offices, what has been rented or sold, at what time, etc.
At the moment I thought about this database design :
Everytime we create a new contract, this contract is about a location or a sale of an item. So we have an Product table (which is the type of product : alarms, alarm watches, etc.), and an Item table, which is the item itself, with it unique serial number. I thought about doing this, because I'll need to have a trace of where a specific item is, if it's at a client house (rented), if it's sold, etc. Products are related to a specific supplier, to whom we can take orders. But here, I have a problem, shouldn't the order table be related to Product ?
The main concern here is the link between Stock, Item, Movement stock. I wanted to create a design where I'd be able to see when a specific Item is pulled out of our stock, and when it enters the stock with the date. That's why I thought about a Movement_stock table. The Type_Movement is either In / Out.
But I'm a bit lost here, I really don't know how to do it nicely. That's why I'm asking for a bit of help.
I have the same need, and here is how I tackled your stock movement issue (which became my issue too).
In order to modelize stock movement (+/-), I have my supplying and my order tables. Supplying act as my +stock, and my orders my -stock.
If we stop to this, we could compute our actual stock which would be transcribed into this SQL query:
SELECT
id,
name,
sup.length - ord.length AS 'stock'
FROM
product
# Computes the number of items arrived
INNER JOIN (
SELECT
productId,
SUM(quantity) AS 'length'
FROM
supplying
WHERE
arrived IS TRUE
GROUP BY
productId
) AS sup ON sup.productId = product.id
# Computes the number of order
INNER JOIN (
SELECT
productId,
SUM(quantity) AS 'length'
FROM
product_order
GROUP BY
productId
) AS ord ON ord.productId = product.id
Which would give something like:
id name stock
=========================
1 ASUS Vivobook 3
2 HP Spectre 10
3 ASUS Zenbook 0
...
While this could save you one table, you will not be able to scale with it, hence the fact that most of the modelization (imho) use an intermediate stock table, mostly for performance concerns.
One of the downside is the data duplication, because you will need to rerun the query above to update your stock (see the updatedAt column).
The good side is client performance. You will deliver faster responses through your API.
I think another downside could be if you are managing high traffic store. You could imagine creating another table that stores the fact that a stock is being recomputed, and make the user wait until the recomputation is finished (push request or long polling) in order to check if every of his/her items are still available (stock >= user demand). But that is another deal...
Anyway even if the stock recomputation query is using anonymous subqueries, it should actually be quite fast enough in most of the relatively medium stores.
Note
You see in the product_order, I duplicated the price and the vat. This is for reliability reasons: to freeze the price at the moment of the purchase, and to be able to recompute the total with a lot of decimals (without loosing cents in the way).
Hope it helps someone passing by.
Edit
In practice, I use it with Laravel, and I use a console command, which will compute my product stock in batch (I also use an optional parameter to compute only for a certain product id), so my stock is always correct (relative to the query above), and I never manually update the stock table.
This is an interesting discussion and one that also could be augmented with stock availability as of a certain date...
This means storing:
Planned Orders for the Product on a certain date
Confirmed Orders as of a certain date
Orders Delivered
Orders Returned (especially if this is a hire product)
Each one of these product movements could be from and to a location
The user queries would then include:
What is my overall stock on hand
What is due to be delivered on a certain date
What will the stock on hand be as of a date overall
What will the stock on hand be as of a date for a location
The inventory design MUST take into account the queries and use cases of the users to determine design and also breaking normalisation rules to provide adequate performance at the right time.
Lots to consider and it all depends on the software use cases.

Access query: Average multiple cells in One column

What Im trying to do is create a shipping estimator if you will. At this point ups and fedex have volume based prices and unfortunately my vendor doesnt supply dimensions for each product. However they do offer weights.
In table one I have Part#, weight, and price of shipping of past shipments.
In table Two I have Part#, weight of never been shipped items.
What I would like it to do:
set up a query that will take products from table 2 and find like weighted items from table 1, average there shipping prices and us this new number as the estimated shipping for the new product. The part im having a hard time wrapping my head around is searching for a range of weights. Lets say my product is 5lbs and I want to get shipping prices of all products ranging form 4.75 to 5.25.
My knowledge of access is somewhat limited. I would really appreciate some guidance here.
SELECT PartsUnshipped.PartNr, PartsUnshipped.Weight,
(SELECT AVG([ShipPrice]) FROM [PartsShipped]
WHERE [PartsShipped].[Weight] >=[PartsUnshipped].[Weight]-0.25
And [PartsShipped].[Weight] <=[PartsUnshipped].[Weight]+0.25) AS Estimated
FROM PartsUnshipped
This is one way to do it. Another way would be to simply join the two tables and run an Avg on the Shipped price but then you would only return non-nulls.

SQL: use calculated field or leave it to the software

I'm modeling a stadium tickets database. I have a TICKET,FAN, CARD, EVENT, SEAT and SECTOR entities (and others). There are areound 40k seats, and 45 sectors. The price is calculated like this more or less:
The EVENT has a base price
The price changes depending on the SECTOR
Depending on the FAN age he could have an ulterior discount
The FAN has a CARD and depending on which type of card he could have a discount
TICKET is linked with a 1:1 to everything except CARD and SECTOR (but SEAT is weak towards SECTOR so he can see its key)
Should I calculate the price in my database? Only if I need to store it? If yes how should I do it, leave it as a calculated field in TICKET?
I hope I've been clear enough, thank for every answer
EDIT: I don't want the sql code to calculate it
I consider it a good idea to have that algorithm implemented in the database, such as to use the same algorithm and code from every app or webservice or whatever you intend to build some day.
I would create a stored procedure to calculate the price. You would call this procedure whenever you want a price calculated.
Once a ticket is issued, its price is fixed however, so you would usually store the price with the ticket. Later you may change discounts, so the same kind of ticket gets cheaper, but the one already sold doesn't of course. That said, use the stored procedure to calculate the ticket price initially. When issuing the ticket, store that current price with it.