Model
Here's a possible model. After I drew it I noticed that the difference with yours is that the product part number is now in the Product table; I think it should be this way as it's a characteristic of the product. Then the Job refers to a Product via its part number, and not viceversa.
Each table uses a surrogate primary key for clarity. This is not really necessary in several cases e.g. in RepairComponent, so feel free to replace it with a composite primary key.
The Product
table stores a product. The field Product.pn
(part number) should identify your product since it is manufactured; the product is then assigned a DMR when it fails and then, if it is repaired, a S/N.
Product
------------------
pn (PK)
DMR (IDX unique)
SN
Job table:
Job
------------------
id (PK)
Product.pn (FK)
due_date
quantity_to_ship
A product can fail multiple times and can be repaired multiple times (many to many relationship).
A product may fail multiple times but each repair concerns only one product, so it's a one-to-many relationship. You can hence have simply one table Repair
(that stores a repair event) referring to Product
.
Failure
------------------
id (PK)
Product.DMR (FK)
description
operation
date
Technician.id (FK)
Repair
------------------
id (PK)
Product.DMR (FK)
disposition
code
date
Technician.id (FK)
RepairComponent
------------------
id (PK)
component_pn
Repair.id (FK)
Technician
------------------
id (PK)
name
Enum vs table
I'm a bit unsure when to use an enum vs creating another table (e.g. disposition can be scrap, repaired, or use-as-is). Am I on the right track?
If you are dealing with an immutable set of operations (i.e. you're absolutely positive that Repair.disposition
will always be one and only one of the options you listed) then it's ok to use an enum. Otherwise, your ER model will be much more flexible if you create another table:
DispositionTypes
------------------
id (PK)
description
as now you can create all kinds of new disposition types e.g. "Repaired", "Use as is", "Scrap", "Sell to China", or "Bury in landfill". In this case, you remove Repair.disposition
and replace it with a FK DispositionTypes.id
instead.
The advantage of this approach is that you can set up authorization levels for Technicians to perform a specific disposal (it is not mentioned in your question but it shows in your model, if I'm not wrong). This is done via a join table Authorizations:
Authorization
------------------
Technician.id (PK) (FK)
DispositionType.id (PK) (FK)
Same talk for RepairCode:
RepairCode
------------------
id (PK)
description
Personally I like to design databases that allow for flexibility, but the choice here it's up to you.
Choice of the DB engine
A MySQL database with InnoDB (which is the standard engine in MySQL) will work fine, so it's a good choice.
What you could do is a design like this:
Product(id,name,description,price,productType)
ProductAttribute(productId,attributeName,value)
Then you would have the possibility to filter for all attributes that are currently used in your database.
If you want to be able to filter for all attributes, even if they are not used in any product at the moment, you'll have to add a table
AttributesForProductType(productType,attributeName)
which contains all possible attributes, and then set up referential integrity (foreign keys) between AttributesForProductType and ProductAttribute. This way you lose the risk of misspelling an attribute name in the ProductAttribute table.
edit: If you take this design this also solves your second question: How to display a details page for every possible product type?
All possible attributes for this product are
select attributeName
from AttributesForProductType
where productType=?
all real attributes for a product with their values are
select attributeName, value
from ProductAttribute
where id=?
and those combined are (off of my head, untested)
select apt.attributeName, pa.value
from Product as p
left outer join AttributesForProductType as apt on p.productType=apt.ProductType
left outer join ProductAttribute as pa on apt.attributeName=pa.attributeName
where p.id=?
Best Answer
As long as you don't have any additional data to store with the "rental" or "sell" property, you don't need a table for it. Just use a
COLUMN manage ENUM('rent', 'sale')
. Then you have to think about prices. The "BuyMe" price seems simple. Renting Models may have a real interesting live, I mean there are a lot of ideas which come in mind, and much more ideas which already live out there, not to speak about the infinite and strange wishes of some Marketing Stuff. So you would be wise enough to point the product to a category of price models. When you have rental, I assume that some products are more or less equal.This Price Category can then be resolved to a Price Model, so you can combine the time of rental together with the Price Model to the real price.
In the beginning start with your original idea of just a price per day (or price per hour), the Price Model contains just this single one value and you multiply number of days (or of hours) with that single number. When it gets more complicated, just extend the table (and the code, of course).
So you have a table:
You refer from pricemodel to pricecategory, since sooner or later you might get different types of customers, which get different prices (Gold Card Members or something like that). So you just add the customertype to pricemodel and are ready for the beginning.
Think about Special Offers, Easter Bundles etc.
products.sale_price
is only set for thesale
case, andpricecategory_id
only forrent
.Have fun with the application and grow! I know of Price Models which tend to need nice Graph Theory Optimization to get calculated, since the different paths have to be compared and of cause the customer gets 'best price' between hour, day, and a lot more.