Reputation: 6645
I'm looking to create a system where users specify shipping prices for their items. The variables I need to cover are the weight band (from in grams to in grams), the price and the countries covered. From this data I can calculate shipping cost by referencing the customers country and the total weight of the basket.
My first thought is something like this:
id from_weight to_weight price us ca gb fr es de it
------------------------------------------------------------------
1 0g 499g 1.99 Y Y N N N N N
2 500g 999g 2.99 Y Y N N N N N
3 1000g 1999g 4.99 Y Y N N N N N
4 2000g 2999g 7.99 Y Y N N N N N
5 0g 499g 4.99 N N Y Y Y Y Y
6 500g 999g 6.99 N N Y Y Y Y Y
7 1000g 1999g 9.99 N N Y Y Y Y Y
8 2000g 2999g 14.99 N N Y Y Y Y Y
However the plan would be to add more and more country options. This would mean adding more columns each time. Is this the best way to structure this kind of data. Any other suggestions
Upvotes: 2
Views: 2946
Reputation: 115530
It seems the rows of your table form groups of related pricing plans. If that's the case, I would suggest you have a PricingPlan
table and a PlanDetail
table.
PricingPlan
-----------
PricingPlanId* PlanTitle
----------------------------------------
1 planA for North America
2 planB for EU
PlanDetail
----------
PricingPlanId* DetailId* FromWeight ToWeight Price
------------------------------------------------------
1 1 0g 499g 1.99
1 2 500g 999g 2.99
1 3 1000g 1999g 4.99
1 4 2000g 2999g 7.99
2 1 0g 499g 4.99
2 2 500g 999g 6.99
2 3 1000g 1999g 9.99
2 4 2000g 2999g 14.99
A third, PlanCountry
table should used so you don't have to add any columns for new countries that you want to relate to a pricing plan (a new row would be added in that table, if for example you want Mexico to be included in planA):
Country
-------
CountryCode* CountryName
-----------------------------
us USA
ca Canada
uk United Kingdom
fr France
es Spain
de Germany
it Italy
PlanCountry
-----------
PricingPlanId* CountryCode*
---------------------------
1 us
1 ca
2 uk
2 fr
2 es
2 de
2 it
1 mx --- Mexico added for planA
Upvotes: 0
Reputation: 10214
normally it is preferred practice to leave the table structure the same, and just add rows to cater for the case that you illustrated. (there are reasons such as optimisation where you can deviate from this)
I would suggest at looking up "3rd Normal Form", if your database complies with the rules to be in 3rd normal form then, you generally end up with a lot less maintenance and easier extendibility down the track.
table1
id | from_weight | to_weight | price
1 | 0g | 499g | 1.99
table2
id | table1id | countrycode | status
1 | 1 | us | Y
2 | 1 | ca | Y
3 | 1 | gb | N
this is how you would query the data
select price from table1
join table2 on table1.id=table2.table1id
where countrycode='us' and status='Y' and
300 between from_weight and to_weight
Upvotes: 4
Reputation: 10786
Yes, I'd say so. Your goal is going to be to find the price for a given weight and country combination, so it should be easy to perform this query:
SELECT price FROM table WHERE $weight > from_weight AND $weight < to_weight AND $country;
And your schema allows that easily. I'd recommend that you select your to_weight such that a value of 499.9 fits in one of the categories, unless weight is restricted to be an integer. I wouldn't worry about adding new columns, that's easy and you can default it to false for any new country.
Upvotes: 0
Reputation: 5730
If you want to avoid adding columns, you can add a 2nd table that has priceID and Country as columns and just remove all the country columns. Then you just make priceID have a foreign key referencing the ID from your first table and you can add new countries as needed.
Upvotes: 0