How to expand this tables to support revision history - mysql

I have 3 tables:
pricelists (pricelist_id, name)
prices (price_id, pricelist_id, price, note)
tickets (ticket_id, price_id, name, time)
So, the main reason for versioning prices is because prices can be changed in future and I want to keep information about past prices for statistics, and I want to tickets has real price, not future changed price.
Can you please give me some example of queries?

I suppose one possible approach is making two price tables instead of two: the first one will store some generic price-related data (like 'note' and 'pricelist_id' link, as these won't change with time), and the second one will store the actual prices (along with, probably, timestamps of their activation - but that's not necessary):
prices (price_id, pricelist_id, note)
price_versions (price_ver_id, price_id, price, started_at, ended_at)
tickets (ticket_id, price_ver_id, name, issued_at)
As you see, you refer to price_versions in your tickets to get the specific price. But you can easily collect the generic price-related information as well (by joining the prices table from there).
This approach lets you construct an additional constraint, checking that issued_at is not before started_at and not after ended_at (it that NOT NULL in the corresponding row). But that's an addition, not a requirement, I suppose.

Related

MySQL Database analyze problem in some table

Tables and relations
Orders
Products
OrderItem
Relation between "Orders" and "Products" is many to many, and "OrderItem" table connects them.
The Problem
When a product is ordered, the product has specific in-price, out-price, and discount. For example, Product A is added at in-price 100, out-price 120, and discount 0, and suppose later, admin changes one of these properties. Now, because the order has a reference to product A, there is a difference between the product details when it was ordered and the present.
I want the ability to be able to update product details. How we can solve this in relational databases.
You need both.
In Product, which is the current value, that changes with a whim.
And in OrderItem, which is what the Product was actually sold for.
This is not a duplicate.
Product (
product-code,
name,
in-price, -- current, changing
out-price,
)
OrderItem (
customer-code, -- FK to Customer
datetime,
product-code, -- FK to Product
in-price, -- actual, historic
out-price,
discount,
quantity
)
When you promise a particular price to a customer, that goes with the customer order as, say, promised_price. That is, you must (for business reasons) have a separate, potentially redundant, "price" to indicate this.
Then whatever the admin does to the in- and out-prices or discount does not impact promises already made.
If the price goes down (or up), you could choose to give the new price to a customer, but that must be a separate, deliberate, action to change the promised_price.
The overhead of having lots of prices floating around for each product is small enough not to worry about the space consumed. An approach like this helps you be an honest businessman, with auditable books.

MS access inventory database advice, querying

I'm building a small inventory database in MS Access (2007), and I have one big dilemma: Should I store purchased (acquired) products/quantities in the same table as sold, with a field for transaction type, or should I separate them in two tables?
I'm working on second option now, but I'm stuck on querying these two tables.
tblProducts: ProductID (PK), ProductCode, ProductName
tblVendorsCustomers: VndCstID(PK), VndCstName, etc..(Vendors can also be Customers and vice-versa)
tblPurchase: PurchaseID(PK), PurchaseNumber(specific), VndCstID(FK), DatePurchased, DueDate
tblPurchaseDetails:PDetailsID(PK), PurchaseID(FK), ProductID(FK), QuantityPurchased, PricePurchased
tblSale: SaleID(PK), SaleNumber(specific), VndCstID(FK), DateSold, PayDate
tblSaleDetails: SDetailsID(PK), SaleID(FK), ProductID(FK), QuantitySold, PriceSold
Two tables (Purchase, Sale) are updating fine. Now, for example, when I want to show a report for a chosen Product, I need to pull data from these two tables, to see purchased quantity (along with Vendor name, date of purchase, and price) and sold quantity (with same set of data) and to calculate available quantity (at a given date). Maybe I'm missing something, but the only way to do this is create two select queries (for each of these tables), than union of these (to pull all transaction data), then a select query of that union, add an identifier field (for row from purchases and row from sales) and criteria for product selection..and I'm stuck on calculating available quantity..I'm guessing sum IIf, but not sure how to use it..
Sorry for such a long post...
Is this the right approach?
Any help or advice would be appreciated.

SQL Database design - three tables: product, sales order, and purchase order - how to store product quantity?

I have three tables: product, sales_order (where I sell products) and purchase_order (where I buy products). Now I can think of two ways of keeping the quantity of each product:
Have a column in the product table called quantity; when inserting into sales_order, I subtract the quantity; when inserting into purchase_order, I add the quantity
Instead of storing the quantity in the product table, I calculate the quantity from the sales_order and the purchase_order table each time I need to get the product table
I am wondering if the second approach is preferable to the first one? I like the second one more because it doesn't store any redundant data; however, I am not so sure if calculating the quantity every time is a bit too much calculation. I am wondering what is the convention and best practice here? Thank you!
I would use the first one. Add a column to the product table in the coding u code -x amount when order and you would then display this in the order table. You could right a script for when the products get to a certain amount it emails you and tells u to replenish stocks. However the second would also work and sql is very powerful so i wouldnt wprry about it being ro demanding as it will prbably work it out faster than we can lol
I prefer the first one because in-memory calculations are faster than issuing select statements to check the sales orders and purchase orders assuming that the number of times the quantity value is retrieved is significantly more than the number of times the quantity value is updated.

Database design: Associating tables of variable types

I am looking for a solution to (something I imagine to be) a common and trivial problem, but I couldn't find the correct words to find solutions on Google.
Starting situation
I have a table orders that is associated to a product and a customer:
orders (id, product_id, customer_id)
The problem
Each order must have a payment associated. These payments come from different payment processors (e.g. Paypal, stripe, Google Wallet, Amazon Payments) and thus have different types of data and data fields associated to them.
I'm looking to find a clean and normalized database design for this.
My own attempt/idea
I could create separate tables for the different types of payments and associate the order from there:
paypal_payment (id, order_id, currency, amount, [custom paypal fields])
stripe_payment (id, order_id, currency, amount, [custom stripe info])
direct_debit_payment (id, order_id, currency, amount, [custom direct debit info])
The problem: With this approach I would need to SELECT from each table for every payment type to find an associated payment to an order, so that doesn't seem very efficient to me.
What is a clean solution to this problem? I'm using MySQL if that is relevant at all.
Thanks for your help! :)
Your Payment table should have all fields that are common to all payments (amount, type of payment, etc) as well as a unique ID.
Variable fields would then be stored in a second table with three columns:
Payment UID (foreign key to the Payment table)
Type (what kind of data this current row is storing, i.e. the name of a custom field for the payment type)
Value
This allows you to associate any arbitrary number of custom fields with each payment record.
Obviously, each payment could have any number of entries in this secondary table (or none if none are needed).
This works quite well as most of the time you wont need the payment type specific info and can do queries that ignore this table. But the data will still be there when you need it.
If you're never going to be using those fields' contents in a where or join clause (which it usually is):
Add a payment method field (an enum or varchar)
Serialize the paypal, stripe, or whatever the client used as json
Store the thing using the most appropriate database type -- text in MySQL, json in Postgres.
A normalized way you could do this is by having a base payment table and extension tables for the other payment types.
All common payment information would go in your payment_base table.
payment_base(payment_id, order_id, currency, amount)
paypal_payment (paypal_payment_id, payment_id, [custom paypal fields])
stripe_payment (stripe_payment_id, payment_id, [custom stripe info])
direct_debit_payment (direct_debit_payment_id, payment_id, [custom direct debit info])

Can I create a table structure with dynamic columns in MySQL?

I've created a stock control database which contains two tables (actually more than two, but these are the two that are relevant to my question): Stock, and Receipts
I would like the link between the stock in the stock table,and the stock in the receipts table to be a little more clearer, this would be fine if a customer could only order one item of stock per receipt, as i'd simply have a StockID column and a Quantity column in the Recipts table, with the StockID column as an FK to the ID in the Stock table, however, the customer can make a receipt with any number of items of stock on it, which would mean i'd have to have a large number of columns in the Receipts table (i.e. StockID_1, Quantity_1, StockID_2, Quantity_2 etc.)
Is there a way around this (can you have like a dynamically expanding set of columns in MySQL) within MySQL, other than what i've done at the moment, which is to have an OrderContents column with the following structure (which isn't enforced by the database or anything) StockID1xQuantity,StockID2xQuantity and so on?
I would post an image of the DB structure, but I don't have enough repuation yet. My lecturer mentioned something about that it could be done, by normalising the database into 4th or 5th normal form?
I'd suggest having 3 tables:
Stock (StockID) + stock specific fields
Receipt (ReceiptID) + receipt specific fields.
StockReceipt (ReceiptID, StockID, Quantity) (could have a StockReceiptID, or use StockID+ReceiptID as Primary Key)
A solution including prices could look like:
Stock (StockID, Price)
PriceHistory (StockID, Price, Date) or (DateFrom, DateTo)
Receipt (ReceiptID, ReceiptDate)
StockReceipt (ReceiptID, StockID, Quantity)
That way you can calculate TotalStockReceiptPrice and TotalReceiptPrice for any receipt in the past.
I suspect this might be what you're looking for:
Stock (StockID, StockPrice)
Receipt (ReceiptID)
StockReceipt (ReceiptID, StockID, Quantity)
SELECT r.ReceiptID, SUM(s.StockPrice * sr.Quantity) AS ReceiptPrice
FROM Receipt r
INNER JOIN StockReceipt sr ON r.ReceiptID = sr.ReceiptID
INNER JOIN Stock s ON sr.StockID = s.StockID
GROUP BY r.ReceiptID
This is all very normalised (again, no idea to what normal form - 3rd?). However it only works if the StockPrice on the Stock record NEVER changes. As soon as it changes your ReceiptPrices would all reflect the new price instead of what the customer actually paid.
If the price can change, you'd need to either keep a price history table (ItemID, Price, DateTo, DateFrom) or record the StockPrice on the StockReceipt record (and then get rid of the JOIN to the Stock record in the above query and make it use sr.StockPrice instead of s.StockPrice)
To do the INSERT you posted below, you'd have to do:
INSERT INTO StockReceipts (ReceiptID, StockID, Quantity, TotalStockPrice)
SELECT 1, 99, 2, s.StockPrice
FROM Stock s
WHERE s.StockID = 99
However it's quite likely that whatever is issuing this receipt (and triggers the INSERT) already knows the price so could just insert the value.
No, relational databases do not allow dynamic columns. The definition of a relational table is that it has a header that name the columns, and every row has the same columns.
Your technique of repeating the groups of stock columns is a violation of First Normal Form, and it also has a lot of practical problems, for instance:
How do you know how many extra columns to create?
How do you search for a given value when you don't know which column it's in?
How do you enforce uniqueness?
The simplest solution is as #OGHaza described, store extra stock/quantity data on rows in another table. That way the problems above are solved.
You don't need to create extra columns, just extra rows, which is easy with INSERT.
You can search for a given value over one column to find it.
You can put constraints on the column.
If you really want to understand relational concepts, a nice book that is easy to read is: SQL and Relational Theory: How to Write Accurate SQL Code by C. J. Date.
There are also situations where you want to expand a table definition with dynamic columns that aren't repeating -- they're just new attributes. This is not relational, but it doesn't mean that we don't need some data modeling techniques to handle the scenario you describe.
For this type of problem, you might like to read my presentation Extensible Data Modeling with MySQL, for an overview of different solutions, and their pros and cons.
PS: Fourth and Fifth normal form have nothing to do with this scenario. Your lecturer obviously doesn't understand them.