I have a simple database of cosmetics. Each product may consist of multiple ingredients. Therefore it is a simple many to many relation and currently I have a database like this:
CREATE TABLE `products` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
PRIMARY KEY (`id`),
);
CREATE TABLE `ingredients` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
PRIMARY KEY (`id`),
);
CREATE TABLE `ingredient_to_product` (
`ingredient_id` INT UNSIGNED NOT NULL,
`product_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`ingredient_id`, `product_id`),
INDEX (`product_id`)
);
However, some ingredients can have many different names. For example: "LINALOOL ESSENTIAL OIL", "LINALYL ALCOHOL" and "3,7-DIMETHYL-1,6-OCTADIEN-3-OL" refers to the same ingredient.
When I am presenting one product, I would like to keep ingredient name as on product label. So in case of one product it will be "LINALYL ALCOHOL" and in case of another product it may be something other, but referring to identical ingredient.
Now I would like to query database for all names of the product by specifying one of its names or by its ID, however how one ID could refer to many names? Do I have to keep two tables: one for specific ingredient in general and another table just for names (relation many names to one ingredient)? Is there any better way?
Ingredients
ID (int) (pkey) (ai)
Name (varchar)
Synonyms
ID (int) (pkey) (ai)
IngredientID (int) (foreign key maps to: Ingredients.ID)
Name (varchar)
Flag (optional; sample values: IUPAC Name, Common Name, Spanish Name, ...)
So yes, for the rules you described, you will at minimum have a primary name, and then a synonym table using the Ingredients.ID
I also introduced a Flag field so that you can programmatically choose when to use a synonym rather than just hard-coding it all the time. For example, if you're listing a product flagged as an industrial chemical, it would be programmed to pull the IUPAC* name
*IUPAC refers to conventions for naming chemicals, and is used by professional chemists almost always, but almost never used in consumer supermarkets: http://www.chem.uiuc.edu/GenChemReferences/nomenclature_rules.html
I suppose the good news is that one name cannot be used for multiple different ingredients, right?
So yes, you probably need an "ingredient name" table, something like
`name` TEXT NOT NULL,
`ingredient_id` INT UNSIGNED NOT NULL
(I'd probably just use name as the PK here, but if your design calls for always using surrogates then also add ingredient_name_id I guess...)
And then the details of the ingredient (except name) would still go in ingredient table. (You could keep a default name in the ingredient table as well, but I wouldn't. If you need that concept, I'd consider adding a "default flag" to the ingredient name table or something like that.)
Since you want to know the name used for each ingredient by a given product, you would replace your current "ingredient to product xref" with an "ingredient-name to product xref".
Why don't you create a separate table for other ingredient name/chemical names, etc. and have it connected with the product id so it can be used separately when needed, and to avoid having any NULL values in your main table.
Related
I am new to databases. This is for a class. I am using MySQL. I will be accessing the database with PHP. I have two tables already. TableA is for products. TableB is for US States. I want to have data about sales of each product in each state. I have considered this is a many to many relationship.
Technique idea #1:
I have considered making a third table, TableC, that has a column for the state names and a column for each product. My issue with this is that I don't know how create a relationship between the product rows in TableA and the product columns in TableC. If I add a product to TableA I want it to automatically add the column in TableC.
Technique idea #2:
Add the product columns to TableB. Same issue as above. Also, seems like a worse design.
Are one of these techniques the right way to do this or is there another technique?
The art and science of making a good schema revolves around finding the best place to put something, or in many cases, the least inconvenient.
Putting sales data in a table that's intended for geographic information is almost always a mistake. Keep your tables focused on one entity, and where information there exists only when related to other tables, make a "join table" that connects the two and put that data there.
For example:
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255)
);
CREATE TABLE states (
id INT PRIMARY KEY AUTO_INCREMENT,
code CHAR(2),
name VARCHAR(255)
);
CREATE TABLE state_sales(
id INT PRIMARY KEY AUTO_INCREMENT,
state_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT
);
You can extend that later to include things like the date/month/quarter the sales happened in and so forth.
I want to design a database in MySQL about categories with options for categories.
Example : Script classified ..
When you want to add ads into the "cars category" you must add some options for this car,but when you add ads in "Apartments for sale category" you must add some options for this Apartment, for example, this image from Dubizzle site illustrates for classified.
When you want to add a car in "cars category", you will show these options
and when you want to add ads in "Apartments for sale category"
you will show these options:
How can I design the database as such?
categories and sub-categories with different options for any categories
create table category
(
id int auto_increment primary key,
catName varchar(100) not null
);
create table catOption
( -- no attempt to share option across multiple categories
id int auto_increment primary key,
catId int not null,
descr varchar(100) not null,
listingOrder int not null -- order listed on screen
-- include FK into category
);
create table listing
(
id int auto_increment primary key,
catId int not null,
title varchar(100) not null,
verbeage text,
price decimal(12,0) not null
-- include FK into category
);
create table listOptions
( -- this table houses a particular listing options (answers if you will)
-- programmer chooses whether or not to save 'blanks'
id int auto_increment primary key,
listingId int not null,
optionId int not null,
answer varchar(100) not null -- you choose datatype
-- include FK into listing
-- include FK into catOption
);
The FOREIGN KEY constraint is used to prevent actions that would
destroy links between tables.
The FOREIGN KEY constraint also prevents invalid data from being
inserted into the foreign key column, because it has to be one of the
values contained in the table it points to.
Categories
First, you need to define your categories table, like categories(id, name, description)
Control Types
As we have seen from the pictures that you have shared, sometimes you have a set of checkboxes, sometimes you have dropdown options, etc. To support this, you need a table like control_types(id, name, description). In your application you will know by the control type value what control needs to be used and how the selections should be understood.
Controls
Now, you can create your controls, like this: controls(id, control_type_id, title). Note that we do not have a category_id in this table, because we want to be able to support the possibility of reusing some controls in multiple categories as long as they are compatible with those. For instance, the price control that you have is needed for both categories. So it is not enough to assume that each control is linked to a single category, quite the contrary, a category can have multiple controls and a control might belong to multiple categories.
Controls of Categories
To achieve the many-to-many relation described in the previous chapter, we create a table where we store the pairs: controls_of_categories(id, category_id, control_id).
Control Items
It's nice that we have the controls, but sometimes they are not trivial. Sometimes we need to select a single value from some options (dropdown) or, we might need to be able to select several options at the same time (checkboxes). To achieve this, we will need another table, like this: control_items(id, control_id, label, value).
Category_sub_category_tab:
CId PK
,CName Text
,SubCatId FK(Category_sub_category_tab(CId))
Options:
ID PK
,OName Text
,CID FK(Category_sub_category_tab(CId))
It a dynamic scheme , first you have to define your categories , controls (text, drop-down ,etc) then you have to define categoryFields this will contian categoryId, field info.. , and you have to define field values table for type drop-down and stuff like that
Minimilized background (ie in bare pseudo code details)
I am making a record keeping (among other things) php/mysql app for my farm. There are lots of types of animals etc that could have pictures (or other records - videos etc.) but just for simplicity I'll only refer to one of each (Goats and Pictures). so say the
tables are approximately like so:
CREATE TABLE BMD_farmrecords_goats (
goat_id INT NOT NULL AUTO_INCREMENT,
goat_name TEXT,
...more columns but whatever, unimportant...
primary_key(goat_id))
CREATE TABLE BMD_farmrecords_pictures (
media_id INT NOT NULL AUTO_INCREMENT,
media_name TEXT,
media_description TEXT,
media_description_short TEXT,
media_date_upload DATE,
media_date_taken DATE,
media_uploader INT, //foreign key constrained to user table but unimportant for question
media_type ENUM('jpg','gif','png'),
media_hidden BOOL,
media_category INT, //foreign key constrained to category table but unimportant for question
PRIMARY KEY (media_id)
So the problem(s):
Obviously a picture could have multiple goats in it so I can't just
have one foreign key in picture to refer to goat.
there are more than one livestock tables that would also make that a poor choice but not worried about that right now
Basically no optimization has been applied as of yet (ie no lengths set, using TEXT rather than varchar(length)) etc; I'm not worried about that until I populate it a bunch and see exactly how long I want everything.
so the question:
what is the best_ way to link a picture to multiple goats (in terms of A) best performance B) best code conformance to standards. I'm thinking I'll have to do an extra table:
create TABLE BMD_farmrecords_goatpictures (
id INT NOT NULL AUTO_INCREMENT
picture_id INT //foreign key to BMD_farmrecords_pictures->media_id
goat_id INT//foreign key to BMD_farmrecords_goats->goat_id
So is there any better way to do that?
Of course with that method I'll probably have to change *_goats table to be a parent *_animals table with then a type field and reference animal_id instead but I'm not worried about that, just about whether or not the extra table referencing both tables is the best method.
thanks;
From the discussion just changing my original idea to use a composite primary key:
create TABLE BMD_farmrecords_goatpictures (
picture_id INT //foreign key to BMD_farmrecords_pictures->media_id
goat_id INT//foreign key to BMD_farmrecords_goats->goat_id
PRIMARY KEY (picture_id, goat_id))
Suppose I have a blog post entity.
It has many attributes
It has comments attached to it.
It has many states (deleted/locked/invisible, etc).
It has many "tags". (keywords, school_id, user_id)
Obviously, comments should be its own table, with a many-to-one relationship to Blog table.
But what about "states" or "tags"? Would you put that in another table? Or would you stick that in many columns?
What about attributes...if they get too big? Because as my website grows, the blog post will have more and more attributes attached (title, author, blah, blah....). What happens if the attribute list goes as high as 100?
Here's a sample:
Again.. It's just a sample.. There are other approaches that you can use.
Here we go:
-- basic-basic blog
CREATE TABLE blog_entry (
blog_entry_id INT NOT NULL AUTO_INCREMENT,
blog_entry_title VARCHAR(255) NOT NULL,
blog_entry_text VARCHAR(4000) NOT NULL,
create_date DATETIME,
state_id INT
);
-- create a look-up table for your blog entry's state
CREATE TABLE be_state (
state_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (state_id)
);
-- create a look-up table for your blog entry's tag/s
CREATE TABLE be_tag (
tag_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (tag_id)
);
-- a table to store multiple tags to one entry
CREATE TABLE blog_entry_tags (
blog_entry_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (blog_entry_id, tag_id)
);
-- a table to store definitions of attributes
CREATE TABLE be_attribute (
attribute_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30)
);
-- now have a table to which you can assign multiple attributes to one blog
-- of course, this is if I understand you correctly
-- where you want to have additional attributes
-- aside from the basic properties of a blog entry
-- and will allow you, if you choose to do it
-- to not necessarily have all attributes for each entry
CREATE TABLE blog_entry_attributes (
blog_entry_id INT NOT NULL,
attribute_id INT NOT NULL,
PRIMARY KEY (blog_entry_id, attribute_id)
-- PK enforces one blog entry may have only one attribute of its type
-- meaning, no multiple attributes of 'location' attribute,
-- for example, for one blog. Unless of course you wrote half the entry
-- in one location and finished it in the next.. then you should
-- NOT enforce this primary key
);
blog_entry - your main table, where the goods go
be_state - define them here, and insert their state_id values in blog_entry.state_id
be_tag - have multiple tags like we do here
blog_entry_tags - since you can possibly have many tags for one blog entry, store them here and insert blog_entry.blog_entry_id and the corresponding be_tag.tag_id together. one tag of its type per blog entry. meaning you can't tag entry#1 (for example) the tag php twice or more.
be_attribute - store attribute definitions here like location, author, etc
blog_entry_attributes - similar to blog_entry_tags where you can assign one or more than one be_attribute to a blog entry.
Again, this is just one approach.
first of all, states should be a tightly structured thing, so you should create separate columns for them. Think about what you need at the beginning, but you can easily add one or two more columns later.
Tags like keywords shouldn't be stored in columns, because the amount is growing rapidly over time. That wouldn't make any sense. So for that, build a table with id and keyword in it and a link table with post_id and keyword_id. You could also omit the keyword_id and directly link post_id and keyword.
Make sure that both columns combined define the primary key, so you can not end up with a keyword stored several time to one particular post.
For attributes it can be the same. It is not a bad practice to create an attribute table with attribute_id, attribute_name and maybe more information and a link table attribute_id and post_id and content.
You can also easily enhance it to be multilingual by using attribute_ids.
Comments are the same, stored in a separate table with a link to a user and a post: comment_id, user_id, post_id, content and maybe parent_id, which can be a comment_id if you want comments to be commentable again.
That's it for a brief overview.
I have this database structure
CREATE TABLE `productinfo` (
`ProductID` int(11) NOT NULL AUTO_INCREMENT,
`ProductName` varchar(255) NOT NULL,
`ProductImage` varchar(255) NOT NULL,
`CategoryID` int(11) NOT NULL,
`SubCategoryID` int(11) NOT NULL,
`ProductBrief` varchar(255) NOT NULL,
`Features` text NOT NULL,
`Specifications` text NOT NULL,
`Reviews` text NOT NULL,
`Price` varchar(255) NOT NULL,
`Status` tinyint(4) NOT NULL,
PRIMARY KEY (`ProductID`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=latin1;
I now I need to turn ProductID, CategoryID, and SubCategoryID into a string like Ps-5678 for the part number. ProductID is the primary key so how do i change the structure of the database. CategoryID, and SubCategoryID are primary keys in other tables so how do i handle this..is it as easy as turning
`ProductID` int(11) NOT NULL AUTO_INCREMENT
into a string..and getting rid of
PRIMARY KEY (`ProductID`)
ideas, suggestions anyone
Primary keys are for the database.
Display names are for end users.
Do not confuse one with another! Don't make a primary key out of something that has a meaning. You will regret it sooner or later.
Having a surrogate key / identity / autonumber as a primary key is a very good idea and is used widely in database design.
You can add a column or even a DERIVED COLUMN and add a unique constraint on it.
I believe it should be that easy.
however you need to determine what string type you want to use
http://dev.mysql.com/doc/refman/5.1/en/string-types.html
Your requirement is unclear. How do you get "PS-5678" fro 3 int columns ? There is only 2 components in your example.
Do you just need to CONVERT the 3 INTs to a single CHAR() string ?
If so, the database is fine, no need to change the table at all !?!?! The three components are already available, correctly seperated, as distinct columns. What you are looking for is merely DISPLAYING the three components as a single string.
It's not clear to me from your question just what you do to product, category, and subcategory to make your part number. I'll assume for the sake of argument that you are concatenating them together, like product 123, category 456, subcategory 789 gives part number 123-456-789 or some such.
I like to use natural identifiers as primary keys whenever practical. But "whenever practical" can be a serious constraint. If your natural identifier is derived by somehow combining three other fields, you have four choices:
Make the primary key be the combination of these three fields. This tends to be a pain. All your joins then must match on three fields, searches must test three fields, etc.
Create a new field that is the concatenation of the three fields, and use this as the priamry key. Then whenever one of the "basic" fields changes, also change this concatenated field. This is a very, very bad idea. Don't do it. It's redundant data, with all the bad things that come from redundant data.
Replace the three separate fields with one combined field. This is worse than #2. Now when you need the individual values, you have to take the field apart.
Give up and create a synthetic key, like a serial number. Use this as the primary key, and then just use the natural key for display purposes. If my natural key requires concatenating or otherwise manipulating three fields, I tend to go with this option.