During normalization of data, can I add my own attributes? - mysql

Can we add our own attributed to the main table during the normalization process.
For example, we have
custid, custname, invoice_date, invoice amount, prod_code, prod_description.
Can I add invoice_ID to the table ?

You have left out a lot of key details making this is a very poor question. Assuming you have have the correct permission/role in any DBMS you can alter any table attributes. The normalisation processes normally comes after you have a draft version of what information you want to represent in each table and then follow the steps of the normalisation process.
http://www.studytonight.com/dbms/database-normalization.php
(Also some advice, you haven't posed any of your DB or even what attributes belong to what table above, in which case if all of the attributes you have listed above belong to the single table this breaks the second/third normal form rule)

An example of a normalised environment:
customers
customer_id*, customer_name
invoices
invoice_id*,invoice_date, customer_id,invoice amount
products
product_id*,product_code, product_description
invoice_detail
invoice_id*,product_id*,quantity
* = (component of) primary key
This assumes that there is a 1:1 relationship between orders and invoices, and that invoices are generated on the date an order is placed.

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.

How do I use lists in MySQL

How do I represent invoices into an MySQL table structure?
The invoice table has the following fields:
id
customer_id
services
tax
total_price
date
...
Now the services can contain one or more articles and, what makes it complicated, various prices. The actual price of a service is negotiated, there are seldom fixed prices because each customer has individual requirements. These items have to be listed on the invoice and the prices of each have to be listed and summarized + tax.
What is the best practice for this purpose? I want to make it normalized if possible, something more sophisticated than just saving an (serialized) array of service => price into the service field, if this is possible at all. Do I use a second table for each service + price and hold a list of IDs with foreign keys?
I think you should follow Has And Belongs To Many relationship. Fr that you use two more tables for this one is 'services' and other is 'invoice_services'
'services' table contain service info and its price etc.
'invoice_services' table will be the join table for 'invoice' and 'services' tables. 'invoice_services' table will contain 'service_id' and 'invoice_id'.
Then you can remove the column 'services' from 'invoice' table.
If you want to maintain negotiable price for each service, then you can add one more field 'custom_price' in 'invoice_services' table.
Then using joins you can fetch the relative data of any invoice.
Hope this may help :)

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.

Creating a relationship between three tables

There are many ways I can think of to hack this together, but I want to know what the best practice is here:
I have three tables. Products, Pricelists and Prices.
One product can belong to many pricelists.
One pricelist can belong to many products.
This is a many to many relationship and as far as I know requires a Junction table (pricelist_products). Which works well.
Now, one product within a pricelist can have multiple prices. A product is only ever given a price once its within a pricelist.
What I've thought about here is using the ID from the junction table 'pricelist_products' as a foreign key within the prices table, but this feels really.... hacky?
Fishy example:
Product 1 - Fishing Rod.
Pricelist A - Fishermen.
Pricelist B - Fishingshop.
Pricelist A, Product 1, price 1:
(Monthly repayments option 1 (no deposit))
Pricelist A, Product 1, price 2:
(Monthly repayments option 2 (with deposit))
Pricelist A, Product 1, price 3:
(Quaterly repayments)
Pricelist B, Product 1, price 1:
(Quaterly repayments)
What I've thought about here is using the ID from the junction table 'pricelist_products' as a foreign key within the prices table, but this feels really.... hacky?
Maybe the issue here is just one of perspective. The purpose of the junction table is to uniquely define each combination within your many-to-many relationship (initially: pricelist to product). This can be achieved in the junction table with the fields product_id and pricelist_id alone, and without the surrogate key id.
Of course, if you defined your junction table with PRIMARY KEY (product_id, pricelist_id), this table would lack the ability to uniquely define combinations when price is considered. So you add a third id to the junction table. It appears you were looking at this field as a necessary surrogate key when defining a relationship between only two tables. However, since the real utility of this field relates to the third table, you might name it price_id instead, name your junction table pricelist_product_price, and define the primary key on all three fields (for example). This more clearly demonstrates the purpose of each field, and so may not feel "hacky" in practice.
I don't know if this is a best practice for database design, but keep in mind that there is no reason you must fully normalize every database. You want good performance with reasonable amount of flexibility and scalability (this can mean one thing for a casual blog, and quite another thing for a small business), and that can often be achieved with some degree of non-normalized design.
Edited to add: Okay, there is one other change I forgot to mention that would fall under "good" design or best practices. In your picture, you have two ID fields in the price table where one would be sufficient. As #Gilbert Le Blanc pointed out, you should try to avoid ambiguous field names like having multiple id fields, even if they are in different tables. This will help you see the utility of your fields, identify natural keys, and eliminate redundancies.
If you would not use anywhere else the relation between products and price lists but for prices then an alternative design is like this:
-Table products with fields: id, others
-Table pricelists with fields: id, others
-Table prices with fields: id (autoincrement), product_id, pricelist_id, price
and you would define index (not unique) on the pair of fields product_id, pricelist_id

Database Approach - Redundant data

I have 3 tables:
products (id, name, price, etc)
orders (id, date, payment_method, etc)
shipments (id, order_id, product_id, address, etc)
My question is: It is correct to keep in shipments table product_id? I keep it here to find information about a shipped product without using orders table.
I would suggest:
products (product_id, name, price, etc)
orders (order_id, date, payment_method, etc)
orderitem (orderitem_id, order_id, product_id, ...)
shipment (shipment_id, order_id, ... )
shipment is kind of redundant - I'd add the address etc into orders...
You can do it, but be careful - if the information in table orders could change, it would be a problem - i.e. if the appropriate record in table orders changes the product_id, the database would be inconsistent.
I do use redundant columns e.g. in static dictionaries.
Also check for the NORMAL FORMS (NF) of database desing, I'm not sure if this redundancy doesn't violate some normal form. But it is up to you if you decide to keep some NF or not.
Following the principles of truth and beauty, you should not store redundant data - it's a great opportunity for bugs to occur, it's ugly, it causes confusion in the minds of future developers.
You're allowed to break the principles of truth and beauty, but only if you run into a problem you cannot solve in any other way. For instance, if you find your queries are just too slow by joining to the orders table, denormalizing the data (which is the technical name for what you're doing) is okay - if you document it and make sure all developers understand.
Just avoiding an extra join in a query doesn't seem like a good enough reason....