How do I Normalize this Auto Parts Database? - php

I am am new to PHP/Databases... But I am picking it up fairly swiftly. What I would like to ask you guys is pretty simple. I want to normalize my database and am not positive how to go about it. I get the concept, but see multiple ways to do it. Figure I'd ask people with some experience.
Here is my Database (2 tables so far):
Brands
Products
***Brands Breakdown:***
1 id int(6)
**Note:** Above, I will probably use 4-Letter codes for each brand instead of primary/int/auto.
2 name text
3 logo varchar(20)
4 phone varchar(20)
5 website varchar(30)
6 contact_name text
7 contact_number varchar(20)
8 contact_email varchar(30)
9 warehouse varchar(20)
10 pricing varchar(15)
11 bio varchar(300)
***Products Breakdown***
id (INT(6) / Auto_Increment)
brand (This is where I'll insert the four letter code for brand)
category (e.g. Brakes)
subCategory (e.g. Brake Rotors)
details (e.g. Drilled and Slotteed 'Razr')
sku (Part #)
minYear
maxyear
make (e.g. Subaru)
model (e.g. Impreza)
subModel (e.g. WRX STi)
description (Paragraph on part describing it)
specs (I imagine this can be expanded on. need cells somewhere for sizes / colors / engine codes / etc.)
msrp
jobber
price
cost
weight (of part)
warehouse (Could be moved to brand's table)
image (URL of image for the part)
So My main question is: Do I make each brand have there own table similar to my current 'products' table? or have 'category' tables? 'subCategories'? How would you guys normalize this data?
I would like to have a solid database while I'm learning this stuff so I learn the right way. Any advice would be appreciated.
UPDATE:
To anyone who comes across this question who is trying to learn how to structure their database, one major thing I was unaware of when I asked this was something called "cardinality". Research this topic and learn how to apply it to your database schemas!

Don't make each brand have its own table. That's not normalization, that's partitioning. Don't do that until your data base gets very large.
It's not clear what your brand table means. I am guessing you mean parts-manufacturer, but I'm not sure. The rest of this discussion assumes that you do mean parts-manufacturer.
Here's my suggestion.
Rename your brand table. Call it "Manufacturer" and split it in two, for Manufacturer and Contact.
Manufacturer:
mfrid (your four letter code, primary key)
mfrname text
mrflogo varchar(20)
mfrwebsite varchar(30)
mfrphone varchar(20)
warehouse varchar(20)
Contact:
mfrid (four letter code) (part of primary key)
contactid (autoincrement) (part of primary key)
contact_name text
contact_number varchar(20)
contact_email varchar(30)
bio varchar(300)
Why is "pricing" an attribute of the manufacturer? What do you mean by "pricing?" Isn't it an attribute of an individual part?
Split your parts table into two. One table will have a row for each part sku. The other will have a table for each application (that is, each make and model of car in which the part may be used). Like so:
SKU:
sku (your stock-keeping unit number, primary key).
mfrid (maker of the PART, not the vehicle in which it fits, foreign key to mfr table).
mfrsku (the brand's stock keeping unit, not necessarily unique in your system)
category (e.g. Brakes)
subCategory (e.g. Brake Rotors)
details (e.g. Drilled and Slotteed 'Razr')
description (Paragraph on part describing it)
saleprice (?)
cost (?)
Application:
ApplicationID (auto incrementing primary key)
make (e.g. Subaru)
model (e.g. Impreza)
subModel (e.g. WRX STi)
firstYear.
lastYear.
Then, you'll need a join table (because each Application can have zero or more SKUs and vice versa; that is, your SKU and Application entities can have many-to-many relationships). In your example, you know that multiple models of Subarus often take the same parts. This schema allows for that.
ApplicationSKU:
ApplicationID
SKU
The trick to normalizing is to understand your application domain. Figure out what entities you have: e.g.
manufacturers like Delco and Subaru
contact people like Joe and Harry
parts like Left Front Wiper Assembly and Rear Wiper Assembly
applications like 1999-2006 Subaru Forester and 1998-2007 Subaru Impreza
Create a table that matches each entity you have. Figure out how you will uniquely identify each entity (in other words, figure out what you will use for a primary key).
Create join tables when you have many-to-many relationships between entities.
Create foreign keys to connect the various entities together.
I hope this helps.

Change products.brand to products.brand_id and have it be a foreign key to brands.id.
Create a categories table and with fields id, name and parent_id(allow NULL) which will house the categories.id of its parent (NULL means top-level category). Alternatively, you can use a nested set model. products would then have a products.category_id field (no subCategory field necessary).

And remember when you get to the part where you actually have orders or put things in the warehouse inventory, store theactual price at the time the action was taken. Price on a product is a lookup, it changes over time but the orders or the value of the item in inventory should be related to the actual costs at the time the record was entered.

One product can fit more than one car -- for example, you might have a wiper blade that fits a 2010 Toyota Camry, a 2009 Scion tC and a 2011 Acura TL. So, you will need to split year/make/model out of the products table, and make a separate table for vehicles (id, year, make, model) and a cross table (id, product_id, vehicle_id) that joins them.

Related

How to handle multiple value selections in PHP and MySQL

I recently took an online PHP / MySQL course and as a way of practicing I make a stock keeping site for a paint shop.
We have a paint table:
paintID: INT, AI
paintType: varchar (e.g. metal, primer, water-based, etc.)
paintPrice: INT (e.g. 10, 15, 20)
paintColor: ???
A colors table:
colorID: INT, AI
colorName: varchar (e.g. blue, red, white, transparent, etc.)
Every paint product comes in one or more colors. So I thought of making a section within the product.php page offering all the colors as checkboxes. While this is simple enough when creating new products,
how can I store the selected colors via PHP in the MySQL database once user presses submit (and what type to give to the paintColor column)
how can I retrieve/show all the possible colors with the chosen ones selected once in 'read-only' or 'update' mode of the product page
The relationship between a Paint and a Color is Many - to - Many.
Conceptually you can have a M <-> M relationship between two entities, but in a concrete implementation, you need a "resolver" table between the two entities. I would probably call this table "paintColor"
It would have something like this in it:
paintColor
----------
paintColorID
paintID (FK to paint)
colorID (FK to color)
As you should be able to discern, this allows you to associate any number of separate color values with a specific paint. I personally don't know if this is actually a feasible design, due to questions regarding whether a specific instance of a paint/color combination doesn't need to have other attributes such that your original design with ColorID as a foreign key in Paint isn't actually what you want.
For example, if a Paint can have different prices for "Gold" vs. "Black" then you have an issue with your current model, unless you attach pricing to paintColor rather than paint. Any data model with a degree of sophistication will have many of these tradeoffs incorporated, and it may not be obvious as to what the reasoning was behind the design.
In your simple model there are probably other foreign key relationships you would want in an actual paint store application, like manufacturer. PaintType should be in a table, and not as a varchar.
MySQL actually has a special datatype that essentially allows you to embed a many to many in one column. It's called an ENUM. If you want to use it for this app, it's not the worse decision you could make, so long as you keep in mind that an ENUM violates the basic rules that all relational databases were supposed to support. For your simple application, it allows you to make a "have your cake and eat it too" which works fine in a simple application. Again, if a paint can have a different price point for 2 different colors that are otherwise the same paint, then you have a problem.
For this reason, often Many to many relationships are more appropriate, and in the way you described your app and the interface you expect, the solution is a Many to many. It's important after you make that choice that you start to learn the implications of that choice for your application.
I usually advise people to think about what the choice entails: If it's a 1-1 relationship then Entity A can have one and only one property B.
If you fill the colors table with preset colors yourself, you can allow the user to select a color from your predefined entries and you store the colorID from the colors table in the the row as foreign key using color in the paint table when you store the user's entry and to retrieve do a left out join on the color table where the ID in the paint row with ID on the row in the color table. The statement would look like...
Junction table
CREATE TABLE juct_paint_color (
paint_key int not null,
color_key int not null,
FOREIGN KEY(paint_key) references paint(paintID),
FOREIGN KEY(color_key) references color(colorID)
)
New insert statement for junction table after you insert the new paint.
INSERT INTO juct_paint_color(paint_key, color_key) VALUES(?, ?)
NEW select statement, you can keep the select the paint however you were doing so before but the two get the color simply used the paintID column from the paint table like so.
SELECT t2.* FROM juct_paint_color t1
LEFT OUTER JOIN color t2
ON t2.colorID = t1.color_key WHERE t1.paint_key = ?;
you could use a transaction or stored procedure in you database to ensure that a new paint row is never inserted without a proper entry to the junction_table, but if you constrict the user input it probably won't be necessary.

Maintain many level hierarchy of tables in database

I have to maintain the data of friend list of friends who liked a particular category post. And this may be at any level. For eg.
if a friend of A who is B like a wanted post. then I ll maintain the record of A’s friends and B’s friend. Basically my requirement is
If user visit my product site I have to tell him/her that you're following friend already visited the same and they actually recommend you to use this and to build confidence that you are on the right way as your friends are also using it. I also want to suggest A that C who is the friend to B is using this product since this time and C suggest to many for using it.
I know this logic is already implemented in good sites.
I am just a starter. So pls suggest me the database for backend and required things for frontend.
Specially this question is to maintain the record on database. So I am asking for the database what should I use not how should I implement that would be next step.
As I am planning to use Graph database for it. In graph either bigdata or Neo4j.
Your ideas are most welcome and will be appreciated. Thanks
I hope my logic may takes you few steps forward
Initially we have to maintain the mutual friends records
foe example
id mut_id
1 2,3,4
Here 2,3,4 are your friends
next we need to maintain the records who has purchased/visited
prod_id buy_id
1 2,1
Now suppose 3 id wants to buy or visit site then we can show that your friend already visited or buyed product
Friends' relations is a classical many-to-many scheme. You need two tables to implement this:
1. A table with personal data, such as name, email etc. (could be more complex like person-properties relation)
2. A table with friends' retaionships data, usually it contains ID pairs of friends that relation is representing and some data about relation itself, such as category (friend/family/classmate etc) , level of affinity (if >0 it means positive relation, <0 negative such as enemies) and so on. Assume first ID is a person this relation belongs to (and can be maintained by), second ID is a person this relation applies to. Usually such kind of tables is constrained to pair of IDs to be unique, so nobody will be able to add same person as a friend twice
Here is some sample:
CREATE TABLE person
(
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255),
email VARCHAR(255),
PRIMARY KEY (person_id)
);
CREATE TABLE relationship
(
id_person INT NOT NULL REFERENCES person(id),
id_person_related INT NOT NULL REFERENCES person(id),
id_category INT REFERENCES relcategories(id),
affinity INT,
PRIMARY KEY (id_person, id_person_related)
);
Note that affinity and id_category fiels are optional and last one requires table relcategories with INT id field to be create first
Visits of one friend to another can also be stored in relationship in a separate field

Advice on database design for portfolio website

So I'm a visual designer type guy who has learned a respectable amount of PHP and a little SQL.
I am putting together a personal multimedia portfolio site. I'm using CI and loving it. The problem is I don't know squat about DB design and I keep rewriting (and breaking) my tables. Here is what I need.
I have a table to store the projects:
I want to do fulltext searcheson titles and descriptions so I think this needs to be MyISAM
PROJECTS
id
name (admin-only human readable)
title (headline for visitors to read)
description
date (the date the project was finished)
posted (timestamp when the project was posted)
Then I need tags:
I think I've figured this out. from researching.
TAGS
tag_id
tag_name
PROJECT_TAGS
project_id (foreign key PROJECTS TABLE)
tag_id (foreign key TAGS TABLE)
Here is the problem I have FOUR media types; Photo Albums, Flash Apps, Print Pieces, and Website Designs. no project can be of two types because (with one exception) they all require different logic to be displayed in the view. I am not sure whether to put the media type in the project table and join directly to the types table or use an intermediate table to define the relationships like the tags. I also thinking about parent-types/sub-types i.e.; Blogs, Projects - Flash, Projects - Web. I would really appreciate some direction.
Also maybe some help on how to efficiently query for the projects with the given solution.
The first think to address is your database engine, MyISAM. The database engine is how MySQL stores the data. For more information regarding MyISAM you can view: http://dev.mysql.com/doc/refman/5.0/en/myisam-storage-engine.html. If you want to have referential integrity (which is recommended), you want your database engine to be InnoDB (http://dev.mysql.com/doc/refman/5.0/en/innodb-storage-engine.html). InnoDB allows you to create foreign keys and enforce that foreign key relationship (I found out the hard way the MyISAM does not). MyISAM is the default engine for MySQL databases. If you are using phpMyAdmin (which is a highly recommended tool for MySQL and PHP development), you can easily change the engine type of the database (See: http://www.electrictoolbox.com/mysql-change-table-storage-engine/).
With that said, searches or queries can be done in both MyISAM and InnoDB database engines. You can also index the columns to make search queries (SELECT statements) faster, but the trade off will be that INSERT statements will take longer. If you database is not huge (i.e. millions of records), you shouldn't see a noticeable difference though.
In terms of your design, there are several things to address. The first thing to understand is an entity relationship diagram or an ERD. This is a diagram of your tables and their corresponding relationships.
There are several types of relationships that can exist: a one-to-one relationship, a one-to-many relationship, a many-to-many relationship, and a hierarchical or recursive relationship . A many-to-many relationship is the most complicated and cannot be produced directly within the database and must be resolved with an intermittent table (I will explain further with an example).
A one-to-one relationship is straightforward. An example of this is if you have an employee table with a list of all employees and a salary table with a list of all salaries. One employee can only have one salary and one salary can only belong to one employee.
With that being said, another element to add to the mix is cardinality. Cardinality refers to whether or not the relationship may exist or must exist. In the previous example of an employee, there has to be a relationship between the salary and the employee (or else the employee may not be paid). This the relationship is read as, an employee must have one and only one salary and a salary may or may not have one and only one employee (as a salary can exist without belonging to an employee).
The phrases "one and only one" refers to it being a one-to-one relationship. The phrases "must" and "may or may not" referring to a relationship requiring to exist or not being required. This translates into the design as my foreign key of salary id in the employee table cannot be null and in the salary table there is no foreign key referencing the employee.
EMPLOYEE
id PRIMARY KEY
name VARCHAR(100)
salary_id NOT NULL UNIQUE
SALARY
id PRIMARY KEY
amount INTEGER NOT NULL
The one-to-many relationship is defined as the potential of having more than one. For example, relating to your portfolio, a client may have one or more projects. Thus the foreign key field in the projects table client_id cannot be unique as it may be repeated.
The many-to-many relationship is defined where more than one can both ways. For example, as you have correctly shown, projects may have one or more tags and tags may assigned to one or more projects. Thus, you need the PROJECT_TAGS table to resolve that many-to-many.
In regards to addressing your question directly, you will want to create a separate media type table and if any potential exists whatsoever where a project is can be associated to multiple types, you would want to have an intermittent table and could add a field to the project_media_type table called primary_type which would allow you to distinguish the project type as primarily that media type although it could fall under other categories if you were to filter by category.
This brings me to recursive relationships. Because you have the potential to have a recursive relationship or media_types you will want to add a field called parent_id. You would add a foreign key index to parent_id referencing the id of the media_type table. It must allow nulls as all of your top level parent media_types will have a null value for parent_id. Thus to select all parent media_types you could use:
SELECT * FROM media_type WHERE parent_id IS NULL
Then, to get the children you loop through each of the parents and could use the following query:
SELECT * FROM media_type WHERE parent_id = {$media_type_row->id}
This would need to be in a recursive function so you loop until there are no more children. An example of this using PHP related to hierarchical categories can be viewed at recursive function category database.
I hope this helps and know it's a lot but essentially, I tried to highlight a whole semester of database design and modeling. If you need any more information, I can attach an example ERD as well.
Another posibble idea is to add columns to projects table that would satisfy all media types needs and then while editting data you will use only certain columns needed for given media type.
That would be more database efficient (less joins).
If your media types are not very different in columns you need I would choose that aproach.
If they differ a lot, I would choose #cosmicsafari recommendation.
Why don't you take whats common to all and put that in a table & have the specific stuff in tables themelves, that way you can search through all the titles & descriptions in one.
Basic Table
- ID int
- Name varchar()
- Title varchar()
etc
Blogs
-ID int (just an auto_increment key)
-basicID int (this matches the id of the item in the basic table)
etc
Have one for each media type. That way you can do a search on all the descriptions & titles at the one time and load the appropriate data when the person clicked through the link from a search page. (I assume thats the sort of functionality you mean when you say you want to be able to let people search.)

Database Schema for News System

I have a news system I'm designing, and it seemed straight-forward at first, but as I've pushed forward with my planned schema I've hit problems... Clearly I haven't thought it through. Can anyone help?
The system requires that the latest 20 news articles be grabbed from the database. It's blog-like in this way. Each article can have sub-articles (usually around 3) that can be accessed from the parent article. The sub-articles are only ever visible when the parent article is visible -- they're not used elsewhere.
The client needs to be able to hide/display news articles (easy), but also change their order, if they desire (harder).
I initially stored the sub-articles in a separate table, but then I realised that the fields were essentially the same: Headline, Copy, Image. So why not just put them all in one big table?
Now I've hit other problems around the ordering. It's Friday evening and my head hurts!
Can anyone offer advice?
Thanks.
Update: People have asked to see my "existing" schema:
articleID *
headline
copy
imageURL
visible
pageOrder
subArticleID *
articleID
headline
copy
imageURL
visible
pageNumber
pageOrder
Will this work? How would I go about letting users change the order? It seemed the wrong way to do it, to me, so I threw this out.
I initially stored the sub-articles in a separate table, but then I realised that the fields were essentially the same: Headline, Copy, Image. So why not just put them all in one big table?
Because referential integrities are not the same.
That is, of course, if you want to restrict the tree to exactly 2 levels. If you want more general data model (even if that means later restricting it at the application level), then go ahead and make a general tree.
This would probably look something like this:
Note how both PARENT_ARTICLE_ID and ORDER are NULL-able (so you can represent a root) and how both comprise the UNIQUE constraint denoted by U1 in the diagram above (so no two articles can be ambiguously ordered under the same parent).
Based on what you've described. I would use two tables. The first table would hold all the articles and sub-articles. The second would tie the articles to their sub-articles.
The first table (call it articles) might have these columns:
+-----------+----------+------+----------+---------+------------+-----------+
| articleID | headline | copy | imageURL | visible | pageNumber | pageOrder |
+-----------+----------+------+----------+---------+------------+-----------+
The second table (call it articleRelationships) might have these columns:
+-----------------+----------------+
| parentArticleID | childArticleID |
+-----------------+----------------+
Not sure if you already accomplish this with the pageNumber column, but if not, you could add a column for something like articleLevel and give it something like a 1 for main articles, 2 for sub-articles of the main one, 3 for sub-articles of a level 2 article, etc. So that way, when selecting the latest 20 articles to be grabbed, you just select from the table where articleLevel = 1.
I'm thinking it would probably also be useful to store a date/time with each article so that you can order by that. As far as any other ordering goes, you'll have to clarify more on that for me to be more help there.
To display them for the user, I would use AJAX. I would first display the latest 20 main articles on the screen, then when the user chooses to view the sub-articles for a particular article, use AJAX to call the database and do a query like this:
SELECT a.articleID, a.headline
FROM articles a
INNER JOIN articleRelationships ar ON a.articleID = ar.childArticleID
WHERE ar.parentArticleID = ? /* ? is the articleID that the user clicked */
ORDER BY articleID
The client needs to be able to hide/display news articles (easy), but
also change their order, if they desire (harder).
On this particular point, you'll need to store client-specific ordering in a table. Exactly how you do this will depend, in part, on how you choose to deal with articles and subarticles. Something along these lines will work for articles.
client_id article_id article_order
--
1 1067 1
1 2340 2
1 87 3
...
You'll probably need to make some adjustments to the table and column names.
create table client_article_order (
client_id integer not null,
article_id integer not null,
article_order integer not null,
primary key (client_id, article_id),
foreign key (client_id) references clients (client_id) on delete cascade,
foreign key (article_id) references articles (article_id) on delete cascade
) engine = innodb;
Although I made article_order an integer, you can make a good case for using other data types instead. You could use float, double, or even varchar(n). Reordering can be troublesome.
If you don't need the client id, you can store the article ordering in the article's table.
But this is sounding more and more like the kind of thing Drupal and Wordpress do right out of the box. Is there a compelling reason to reinvent this wheel?
Create a new field in news(article) table "parent" which will contain news id of parent article. This new field will be used as a connection between articles and sub articles.
As SlideID "owns" SubSlideID, I would use a composite primary key for the second table.
PrimaryKey: slideID, subSlideID
Other index: slideID, pageNumber, pageOrder (Or however they get displayed)
One blog post I prefer to point out about this is http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary_keys.aspx as it explains why very nicely.
If you're replying on Auto_Increment, that can be handled too (with MyISAM tables), you can still set subSlideID to auto_increment.
If you're likely to go to a third level then merge - follow Branko above. But it does start to get very complicated, so keep separate for 2 layers only.

How should I create this customized e-commerce database model?

I am building an e-commerce website from scratch and have to make a special product configuration page.
It's only 1 type of product, but it is configurable on several levels:
Color (about 4 different options). Value is a VARCHAR.
Material (about 10 different options). Value is a VARCHAR.
Size (About 30 different options). Has 2 Values, a width column and a height column.
Finish (About 20 different options). Value is a VARCHAR.
Other various VARCHAR options etc.
My question is what would this look like in a typical MySQL database. Do I have a table for each type of option or just one table and somehow give it enough columns and have it store all options? I will need to store orders and be able to store the information for the order in a table as well.
I also want to be able to have off the shelf products that aren't customizeable, just like a normal store.
Any help is appreciated!!
I suggest that you go with one master table, with all of the product information, and a slew of lookup tables, that connects to the master table.
It should look like this:
Product_table:
ID primary key,
ColorInt int foreign key lkp_Color_table.ID,
Material_int foreign key lkp_Material_table.ID,
// snip the rest
And here's the lookup table:
lkp_color_table:
ID primary key,
ColorStr varchar,
description varchar
lkp_Material_table:
ID primary key,
MaterialStr varchar,
description varchar
The Product_table can look like this:
ID||ColorInt||Material
1 ||1 ||1
2 ||1 ||2
Whereas the lkp_color_table can look like this:
ID||colorstr||description
1 ||red ||red color
2 ||blue ||blue color
Note that lkp_color_table can contain unused color , same goes for other lookup tables. So if you have 30 possible colors, you just have to populate lkp_color_table with 30 items, and so on.
There is no need to create a separate Product_id for each color-material- combination, you just have to create a product_id if you use it.
2 + N tables:
Products (every single product in the catalog has a record here
SpecialKindOfProduct (Your configurable product type, a product_id, and a bunch foreign keys to lookup tables (color_id, size_id, etc)
N Lookup tables (colors, sizes, etc)
When you add a second kind of configurable product in the future, you just create AnotherSpecialKindOfProduct.
Hope this is clear enough to follow.
The main advantage is that all your products have some shared attributes (the columns of "Products"), but can have extended attributes as well.
You can easily select everything you need by LEFT JOINing Products to SpecialKindOfProduct, etc.
I'd say that you'll need:
OrderTable (OrderID, CustomerID, Date, Price, Shipment, ...)
OrderProductTable (OrderID, ProductID, Quantity)
ProductTable (ProductID, StandardBit, ColorID, Option2ID, ..., OptionNID);
StandardBit - to know if product is standard or configurable.
CustomerTable (CustomerID, ...)
ShipmentTable ()
OptionTable for every configurable option (OptionID, Description).

Categories