mysql best way to manage product sizes - mysql

I am developing product database, for sizes i created a separate table PRODUCT_SIZE(id,sizetext)
e.g. (1,'Small') ,(2,'Large'), (3,'Extra Large'),...
I provided These sizes list as checkbox, when a product is added, all possible sizes can be selected against current product.
e.g. for T-Shirt, SMALL, and LARGE sizes selected.
these 2 Sized are available against each new stock purchased entry.
Now i came to know, that there can be different size units, some items can be in inches, some in kg, and some in meters.
I have a altered solution in mind:
to alter table
PRODUCT_SIZE(id,sizetext, UNitType);
Now it can be: (1,'5','KG') ,(2,'10','KG'), (3,'2.5'.'Inches'),...
Is ther any better approch, suggestion?

It seems like you're forcing 'clothing size', 'weight' and 'length' into one 'size' attribute.
Try these tables:
product (product_id, name)
"Nike t-shirt"
attribute_group (attribute_group_id, name)
"Shirt size", "Weight", "Length", etc.
attribute_value (attribute_value_id, attribute_group_id, name)
"Shirt size" would have rows for "Small", "Large", etc.
product_attribute (product_id, attribute_value)
"Nike t-shirt" is "Large"
Add a "display order" to attribute_value, too (so "Small" can be displayed before "Large").
Do this for your other attributes, too.
I've done this for a production site, and I think it worked well.
Good luck.

Instead of making a seperate table for this, why don't you just put all of your dropdown options in an application scoped variable? Then you can just add that data right into a field in product as a string and deal with the different options/units programmatically.

I made a database storing clothes where the sizes were a few types.One article has sizes like xs s m l other is
26 27 28 29 30 and so on.
I decided to do this:
# on one side in the script i define size types and names;
$sizeTypes[1] = [XS, S, M, L];
$sizeTypes[2] = [29, 30, 31, 32];
#The and so on
#and on the other side in the database, there are just two columns
size_type_id(int) | size_qty |
# so if I have one article with 3 pieces of size S 2 pieces of size M and 5 pieces of size L the database will store:
size_type_id| size_qty |
1 |0:0;1:3;2:2;3:5|
then in the script I just translate it so that 0 of type 1 is XS 1 of type 1 is S 2 of type 2 is 31 and so on

Related

Relational database trouble in a custom e-commerce web application

First of all, I apologize for the bad English you are about to read...
I'm trying to develop a little e-commerce web application (from scratch - without using platforms like Magento, OpenCart, Shopify...) for a pizza delivery in the city where I live. The restaurant also sells some italian food, like pasta, fish and meat.
I'm stuck in a relational database problem, I will explain what I did in the database. I will write the tables structures followed by some examples records.
Unlike the pastas, the pizza's price varies according to size (an attribute).
The data will be displayed in the following way (please see the picture below):
Showing a pizza example record in the front-end. When the user selects the size, the price will be displayed below and two controls to add or substract the quantity of that product (with that size) will also be displayed.
This is the case of one pizza with one attribute (an attribute that affects the price), because there are some attributes that not affects the price, i.e: the cooking or doneness. Another case is that a product that have more than one attribute that affect the price.
In summary:
Product without attributes, it has an only one price.
Product with only one attribute that affect the price.
Product with two or more attributes that affect the price.
MySQL Tables:
Categories(ID, name):
1, Pizzas
2, Pastas
_
Products(ID, category_id, name, description)
1, 1, Margherita, Lorem ipsum
2, 1, 4 Stagioni, Lorem ipsum
3, 1, Capricciosa, Lorem ipsum
4, 2, Bologna, Lorem ipsum
5, 2, Pesto, Lorem ipsum
_
Attributes (ID, name)
1, Size
2, Cooking
_
Meta_attributes(ID, attribute_id, name)
1, 1, Small
2, 1, Medium
3, 1, Big
4, 2, Blue
5, 2, Medium well
6, 2, Well done
7, 2, Overcooked
_
meta_attributes_values(ID, product_id, meta_attrib_id, value)
1, 1, 1, 12
2, 1, 2, 16
3, 1, 3, 19
4, 2, 1, 14
5, 2, 2, 18
6, 2, 3, 20
_
In this schema, a product can have a value if and only if it has a meta_atrib and in order to have an meta_atrib it must have an attrib. But the pasta is "linear" it no have any attrib, for one pasta product there are only one price.
Questions:
How should be the database to handle all these cases?
What about special cases where one attribute influences another? For example, suppose that the price of a pizza varies according to its size (this is true), but suppose that it also has an attribute called "extra" and that the price of the extra attribute varies according to the size of the pizza, Because being larger will require more. I know that the example is not very clear but I hope I have made the case clear and express myself well.
Thanks for reading!
It's important to note that the schema you've described doesn't represent an actual order, it represents the abstract concept of a pizza. A graph of Products, Attributes, Meta-Attributes, and Values is far more complicated than an itemized order needs to be.
What's really in an order? There are Products, each of which has a base price; and there are, as you note, things which affect the price of a Product. These modifiers come in at least two types:
Additive modifiers tack on a flat sum to the base price. A "medium" pizza costs $4 above the base; a "large" costs $7 more.
Dependent modifiers change the base price after it's adjusted by additive modifiers. The simplest form of dependent modifier is a multiplier: whatever the adjusted price of a pizza is, one with "extra hot peppers" costs 0.10x more than that.
With any luck, that's all you have to deal with. If "extra peppers" instead costs $0.50 on a small, $0.60 on a medium, and $1.00 on a large, you have to track all three and correlate with the size modifier since the addition isn't a consistent function of adjusted price. Treating additive modifiers like size independently -- for example, by having base, medium, and large prices in Product -- may be more effective in that case.
It would be possible to achieve a simpler representation still by treating products and attributes identically and storing them in a single table with a foreign key to itself to represent the parent-child relationship. Effectively, you'd have no Products, only Attributes. And "Margherita" would be an Attribute that adds $12 to an item base price of $0.
But getting back to the concrete, if you need to track Orders with Order_Items too, even a one-row-per-attribute solution is unwieldy since you have a profusion of foreign keys in each line item of the order. In this case, it may be best to store your sub-items (or everything, if you roll it all into one table) in a JSON field, such that your Order_Items table looks like this:
id order_id subtotal attributes
1 1 17.60 [{"name": "Margherita", "adds": 12.00}, {"name": "Medium", "adds": 4}, {"name": "Extra hot peppers", "multiplier": 0.10}]
2 1 12.00 [{"name": "Pesto", "adds": 12.00}]
This is a) denormalized and b) breaks referential integrity. Both of these, in this instance, are good things! If you ever adjust prices or even take something off the menu, you don't want to screw up your bookkeeping or trip a foreign key constraint error.

How to get rid of arrays in mysql database?

Dining room specializes on complex dinners. Have collection of recipes (each of them collect rates of the products). Every product have changeable price.
Is it the best design?
Recipe(r_id, r_title, r_category, r_price)
Product(p_id, p_title, p_price)
UsingProducts(r_id, p_id, amount)
I am just not sure about UsingProducts..
The design looks quite okay.
As zerkms mentioned, you're lacking units. That doesn't have to be a problem, as your product can be "100 g flour" so the unit is implicit. However, when printing the recipe, you would print "5 x 100 g flour" instead of "500 g flour". It would also print "10 x 100 g flour" instead of "1 kilo flour".
Just think about whether this an issue for you and if you even need unit conversion like 1000 g = 1 kilo.
Another point is your category. So a recipe can only belong to one category. So you won't have something like "vegetarian" and "soups" with the problem where to place a vegetarian soup, but use distinct categories instead. Okay. However, don't you want a table for them, so to be able to easily select them? If you want to stay with this design you should at least make them an enum column (something special in MySQL), so you dont mistakenly have recipes in "soups" and others in "suops".
At last: What is the r_price for? Shouldn't that be the the sum of all sub prices (product price x amount)? Don't hold data redundantly. This must not be done. Otherwise inconsistencies can occur (e.g. 10$ + 10$ = 30$). Remove r_price from table recipe to have a normalized database.

Comparision of data in huge databases

I have a database in mysql which has a collection of attributes (ex. 'weight', 'height', 'no of pages' etc) and attribute values (ex. '30 tons', '12 inches', '2 pgs' etc) and mapped with the respective product ids.
The data has been collected from different sites and hence the attribute values have different formats (ex. '222 pgs' or '222 pages' or '222') (ex2. '12 inches', '12 meters', '12 cms').
What I need to do is that I have to compare the values of same attributes of different products. So I have to compare '222 pgs' with '222 pages' for all the attributes which differ in formats.
There are around 4000 attributes and the number will increase further. Is there any way to compare these without having to assign each attribute a specific type individually? Or what is the fastest way to compare these?
Well, until they invent a clairvoyant computer, a human being will have to tell it that pgs and pages mean the same thing and that inches and meters are convertible.
You'll have to sanitize the data one way or another. I'd probably start by identifying units that measure the same dimension1 and common aliases2 for each unit, then parse the data to split the quantity from the unit and normalize3 the unit. Once you have done that, the data becomes directly comparable.
But all this is really just a remedy for the problem that should not have been there in the first place, were the database designed properly.
1 A "mass" is a dimension measured by units such as kg, t, lb etc. A "length" is a dimension measured by m, km, in etc.
2 E.g. an in and inch denote exactly the same unit, pgs and pages are the same etc.
3 I.e. make sure a particular dimension is always represented by the same unit: for example convert all lengths to m, all masses to kg, all pages to pages etc.
You haven't explained what you want to do after you find out that attributes for a pair of products differ (while still meaning the same thing).
I.e.: if I see that in Instance A has field Length set to "12 pgs" and Instance B has Length reporting "12 pages" what do you do?
List this? Autocorrect? Drop one of the two values? Open a window for a human user to correct?
Personally I'd go for a "select attribute,count(*) from X group by attribute" so that you can find out the most common spelling of the unit, and then you can also write corrective scripts that may automatically convert ".. pgs" to " pages" as soon as you have decided the correct representation.
Of course this will not help at all unless you enforce correct spelling of the units, and this requires for sure better input-output filters, including the main UI, but also any kind of bulk uploader utility you may use to create or update products.
A redesign of the DB to add "Unit" as an extra, categorized attribute for each measure would also help a lot.

Saving user's height and weight

How should I store a user's height and weight in a MySQL database such that I can use the information to find users within a certain height or weight? Also, I will need to be able to display this information in either English or metric system.
My idea is to store the information for height in centimeters and weight in kilograms (I prefer metric over English). I can even let the user enter their information and English system, but do the conversion to metric before saving. I think converting kilograms to pounds might be easy to do in SQL, but I'm not sure how easy it would be to convert 178 centimeters to 5'10" (rounded slightly down).
Should I be saving English and metric values in the database so that I don't need to do conversions when I do my queries? Sounds like a bad idea to store derived/computed values.
There are several ways... one is to just have two numeric columns, one for height, one for weight, then do the conversions (if necessary) at display time. Another is to create a "height" table and a "weight" table, each with a primary key that is linked from another table. Then you can store both English and metric values in these tables (along with any other meta info you want):
CREATE TABLE height (
id SERIAL PRIMARY KEY,
english VARCHAR,
inches INT,
cm INT,
hands INT // As in, the height of a horse
);
INSERT INTO height VALUES
(1,'4 feet', 48, 122, 12),
(2,'4 feet, 1 inch', 49, 124, 12),
(3,'4 feet, 2 inches', 50, 127, 12),
(3,'4 feet, 3 inches', 51, 130, 12),
....
You get the idea...
Then your users table will reference the height and weight tables--and possibly many other dimension tables--astrological sign, marital status, etc.
CREATE TABLE users (
uid SERIAL PRIMARY KEY,
height INT REFERENCES height(id),
weight INT references weight(id),
sign INT references sign(id),
...
);
Then to do a search for users between 4 and 5 feet:
SELECT *
FROM users
JOIN height ON users.height = height.id
WHERE height.inches >= 48 AND height.inches <= 60;
Several advantages to this method:
You don't have to duplicate the "effort" (as if it were any real work) to do the conversion on display--just select the format you wish to display!
It makes populating drop-down boxes in an HTML select super easy--just SELECT english FROM height ORDER BY inches, for instance.
It makes your logic for various dimensions--including non-numerical ones (like astrological signs) obviously similar--you don't have special case code all over the place for each data type.
It scales really well
It makes it easy to add new representations of your data (for instance, to add the 'hands' column to the height table)
I would do it the way that you have said you would like to do it, but on the converting part, you would not convert 178 centimeters to 5'10", you would convert it to 70", then if need be, convert that into 5'10".
Think of 5'10" as either 70" or 5.8333333'. In that case, converting betwen 70" or 5.83333 is just a multiplication, so its easy to store in the db as centimeters if you so choose.
The issue of what the user sees is a presentation issue and nothing to do with the database.
I agree that storing computed values in this case is not ok. Your choices are perfect.
However, I would do the computations at the application level and query the DB with those values - depending on the language your application is written in , I am sure there are plenty o libraries/modules that are made that can compute those transformations.
Edit - to address the issue of storing computed values in DB:
While this is considered to be a bad practice in working with DBs, I usually am not 100% against this practice - just 90%.
I tend to store computed values in DB only when the computations are complex and would take enormous resources to get to the result wanted - this is clearly not the case.
If you would store computed values here you would have only the disadvantages of this technique - when modifying a record, you would have to modify the data in multiple places to keep the consistency of your DB

Stock management of assemblies and its sub parts (relationships)

I have to track the stock of individual parts and kits (assemblies) and can't find a satisfactory way of doing this.
Sample bogus and hyper simplified database:
Table prod:
prodID 1
prodName Flux capacitor
prodCost 900
prodPrice 1350 (900*1.5)
prodStock 3
-
prodID 2
prodName Mr Fusion
prodCost 300
prodPrice 600 (300*2)
prodStock 2
-
prodID 3
prodName Time travel kit
prodCost 1200 (900+300)
prodPrice 1560 (1200*1.3)
prodStock 2
Table rels
relID 1
relSrc 1 (Flux capacitor)
relType 4 (is a subpart of)
relDst 3 (Time travel kit)
-
relID 2
relSrc 2 (Mr Fusion)
relType 4 (is a subpart of)
relDst 3 (Time travel kit)
prodPrice: it's calculated based on the cost but not in a linear way. In this example for costs of 500 or less, the markup is a 200%. For costs of 500-1000 the markup is 150%. For costs of 1000+ the markup is 130%
That's why the time travel kit is much cheaper than the individual parts
prodStock: here is my problem. I can sell kits or the individual parts, So the stock of the kits is virtual.
The problem when I buy:
Some providers sell me the Time Travel kit as a whole (with one barcode) and some sells me the individual parts (with a different barcode)
So when I load the stock I don't know how to impute it.
The problem when I sell:
If I only sell kits, calculate the stock would be easy: "I have 3 Flux capacitors and 2 Mr Fusions, so I have 2 Time travel kits and a Flux Capacitor"
But I can sell Kits or individual parts. So, I have to track the stock of the individual parts and the possible kits at the same time (and I have to compensate for the sell price)
Probably this is really simple, but I can't see a simple solution.
Resuming: I have to find a way of tracking the stock and the database/program is the one who has to do it (I cant ask the clerk to correct the stock)
I'm using php+MySql. But this is more a logical problem than a programing one
Update: Sadly Eagle's solution wont work.
the relationships can and are recursive (one kit uses another kit)
There are kit that does use more than one of the same part (2 flux capacitors + 1 Mr Fusion)
I really need to store a value for the stock of the kit. The same database is used for the web page where users want to buy the parts. And I should show the avaliable stock (otherwise they wont even try to buy). And can't afford to calculate the stock on every user search on the web page
But I liked the idea of a boolean marking the stock as virtual
Okay, well first of all since the prodStock for the Time travel kit is virtual, you cannot store it in the database, it will essentially be a calculated field. It would probably help if you had a boolean on the table which says if the prodStock is calculated or not. I'll pretend as though you had this field in the table and I'll call it isKit for now (where TRUE implies it's a kit and the prodStock should be calculated).
Now to calculate the amount of each item that is in stock:
select p.prodID, p.prodName, p.prodCost, p.prodPrice, p.prodStock from prod p where not isKit
union all
select p.prodID, p.prodName, p.prodCost, p.prodPrice, min(c.prodStock) as prodStock
from
prod p
inner join rels r on (p.prodID = r.relDst and r.relType = 4)
inner join prod c on (r.relSrc = c.prodID and not c.isKit)
where p.isKit
group by p.prodID, p.prodName, p.prodCost, p.prodPrice
I used the alias c for the second prod to stand for 'component'. I explicitly wrote not c.isKit since this won't work recursively. union all is used rather than union for effeciency reasons, since they will both return the same results.
Caveats:
This won't work recursively (e.g. if
a kit requires components from
another kit).
This only works on kits
that require only one of a particular
item (e.g. if a time travel kit were
to require 2 flux capacitors and 1
Mr. Fusion, this wouldn't work).
I didn't test this so there may be minor syntax errors.
This only calculates the prodStock field; to do the other fields you would need similar logic.
If your query is much more complicated than what I assumed, I apologize, but I hope that this can help you find a solution that will work.
As for how to handle the data when you buy a kit, this assumes you would store the prodStock in only the component parts. So for example if you purchase a time machine from a supplier, instead of increasing the prodStock on the time machine product, you would increase it on the flux capacitor and the Mr. fusion.