Storing pincodes and shipping charge for each pincode - mysql

I'm Creating a E-Commerce application using Magento. I need to build a custom Shipping module for this. Currently i'm designing the tables to store data.
The issue is when a customer places an order i need to get the Shipping companies who provides service in that locations ie Pickup and delivery. Once i have the details of the shipping company i need to get the shipping charge to that particular location. I have asked a question about how to store pincodes and shipping company detail.
The suggestion i got was to create a table like as follows
Shipping Companies
--------
ID (int, PK)
Name (string)
Pincodes
--------
ID (int, PK)
Pincode (string)
These entities have a many-to-many relationship. So create a table to link them:
Shipping Company Pincodes
--------
ID (int, PK)
Shipping Company ID (int, FK)
Pincode ID (int, FK)
Pickup (bit)
Delivery (bit)
Using this table structure i can track the shipping companies which will provide pickup and delivery . However once i have these shipping company ids, the next step i need to do is get the shipping charges to deliver the product at that location. One suggestion from one of my colleague was to store the range of pincodes instead of storing all the pincodes. And row will store the rate for multiple shipping company For example:
Pincode | Fedex Rate | DHL Rate | UPS Rate
----------------------------------------------------
67 - 69 7.7 6.5 5.5
But since i'm storing a range of pincodes how will i identify if shipping company does not provide delivery or pickup in any pincode in that range. Also is there any other better method to store the shipping rates for pincodes. There are actually around 19000+ pincodes. I thought of storing individual rates for each pincode and shipping company, but that will make the table very huge.

Tens of thousands of rows is small for MySQL/MariaDB. I would forego the Pincodes table as well as the surrogate ID in the Shipping Company Pincodes table and use the Shipping Company ID and Pincode as a composite primary key. The Pincode looks like an integer (no less efficient than a surrogate id) and a meaningful natural (externally defined) key, meaning you'll likely need it frequently in queries. If it forms part of your primary keys, it'll be conveniently available and indexed by default. I would also add a Rate column to this table.
To summarize:
Shipping Companies
--------
ID (int, PK)
Name (string)
Shipping Company Pincodes
--------
Shipping Company ID (int, PK/FK)
Pincode (int, PK/FK)
Pickup (bit)
Delivery (bit)
Rate (decimal)

This addresses a more complex question, so it is not really addressing the one asked.
Is the main query is "What will the companies charge to ship from Pin 12345 to Pin 29876?"
Plan A is a 360 million row table with all possible start/end pins. This may be the best, since it is very efficient to do SELECT ... WHERE pin_from = $from AND pin_to = $to while having PRIMARY KEY(pin_from, pin_to). This table might take 20GB; is that OK? The SELECT might typically take 10ms.
Plan B, which you alluded to, would need a table like
CREATE TABLE Rates (
from_a, from_z, -- min and max pins for source pin range
to_a, to_z, -- ditto for destination
fedex DECIMAL(6,2) NULL -- NULLable in case fedex does not run that route
etc.
PRIMARY KEY(from_a, from_z, to_a, to_z)
) ENGINE=InnoDB;
The table would be much smaller. The query is something like:
SELECT IFNULL(fedex, 'N/A') AS Fedex, ...
FROM Rates
WHERE $from BETWEEN from_a AND from_z
AND $to BETWEEN to_a AND to_z;
The problem is that there is no good way to index this. This encounters two problems -- testing within a range in that way is not optimizable, and it is essentially a 2-dimensional problem.
If the table is only thousands of rows, then a table scan is not "too bad". If it is millions of rows, it would probably be too slow.
Loading the table would be a lot of challenging code -- you don't want any overlapping rectangles. Updating the table would be even more challenging.
Plan C... Perhaps a SPATIAL index is exactly what you need. The (x,y) of a Spatial "Point" is the pair (pin_from, pin_to). Sorry, I don't know where to take it next.
Plan D... This is a variant on Plan B, but it greatly improves the efficiency. It adds 2 columns; x, y. They have values 0..190, calculated as floor(pin/100). The idea is to have 190*190 "buckets". In each bucket is every rectangle (a la Plan B) that has a point in the bucket. Yes, that means some rectangles will show up in more than one bucket; this is a small price to pay for significant performance improvement.
PRIMARY KEY(x, y, from_a, from_z, to_a, to_z)
SELECT ...
FROM Rates
WHERE x = FLOOR($from/100)
AND y = FLOOR($to/100)
AND the rest of Plan B's WHERE
Since a "bucket" cannot have more than 100*100 rows, and they are "clustered" in the table, the scan is reasonably bounded. If, say, the average bucket is 10 pins by 10 pins, then the average bucket has only 100 rows -- quite efficient.
Sorry, loading and updating is still complex.
(I picked 100x100 for bucket size; there may be a better choice, based on the size of the typical rectangle. Note the advantage of 100: it leads to 0..190 range, allowing x and y to be small: a 1-byte TINYINT UNSIGNED.)

Related

MySQL - Best practices for tables with custom and default entries

I want to have a list that consists of default and custom entries. So, for example, on my software when a dealership is created and want to put a car in their inventory I want them to be able to select from a list of types of cars that already exists in the database and also from types of cars they will be adding as needed but only for that dealership.
How should I build this?
Should I have a table with the default types and another one with the custom types of that dealership and when requested I return both? -> each query will have to access 2 tables.
Should I have a single table with a column with the dealership ID and when requested return all that have the dealership ID and all that don't have any dealership ID (the default ones)? -> each query will have to return results with both no ID and dealership ID.
Should I have a single table with a column with the dealership ID and every time a new dealership is created I duplicate the default entries but their ID on it? -> Can really become monstrous and with duplicate entries.
Is there a better way to do this?
Example:
I just created a dealership and when I try to add a car to my inventory I see the options Mercedes, Volkswagen and Kia. But I want to add a Jaguar and it's not on the list. I want to add it only to my dealerships's list, so the next time I try to add a Jaguar the option is already there.
PS: I have tried searching for a solution for this but couldn't find anything.
You definitely should avoid creating a separate table for each dealership.
Your second choice is best. You may want a table with columns like this:
id
zone_id
dealership_id
maker_id
maker_name
model_id
model_name
model_number
Then you can run queries like this:
SELECT model_name, model_number
FROM tbl
WHERE (dealership_id = :current_dealer: OR dealership_id IS NULL)
AND (zone_id = :current_zone: OR zone_id IS NULL)
AND (maker_id = :current_maker: OR maker_id IS NULL)
You can write a query like this to express the precise business rules for the choices for each dealer site.
Why add zones? Some vehicle makers have regional variations on their products. For example, internal combustion engines in California have more stringent regulations about exhaust than the rest of the US. The vehicle makers have zone offices in California to help coordinate that. Subaru sells a version of its vehicles specifically designed for New England in the Eastern US.

MySQL: What is the most performant way of storing a whole year (365 elements) in MySQL?

Within a project, I have to store the daily availability of different meeting rooms. So let's suppose around 1.000.000 meeting rooms, where each meeting room is in a city, and a city could have hundreds of meeting rooms.
I would also like to be able to make SELECT Queries entering the city and the availability that I need, so I would like to get a list of the available meeting rooms for a day, or set of continues days, in a concrete city.
I have one table called "MeetingRoom", when I store the city and the name of the meeting room, but my design question is how to design the availability part:
Is it better in terms of performance to have a binary array that stores the 365 days of the year with a '1' or '0' according to the availability of the meeting room?
Is it better in terms of performance to have another table called "Availability" that stores a DATE and a BIT with the availability, and then JOIN both tables for each meeting room that exists in a city?
Could it better another option I don't have in mind?
I wonder what querying time would be optimal having around 1.000.000 meeting rooms, and searching for the meeting rooms in a city and available for concrete days. Is it crazy about thinking in database responses below 100 ms?
Some colleagues told me that I should also consider to migrate to MongoDB or NoSQL approach. I don't know if a change of DB could fit better with my issues, or if it don't. Any comment about this?
Thank you very much for the help!!
I don't know if this will help, but if it doesn't, please write me to delete the answer.
Instead of these options you may want to consider that in the "Availability" table to store only the id(surrogate) of the room and the date on which it is reserved. So when you select the data and join both tables you will get only the reserved rooms. I personally think that there is no point of storing all of the room-date relations with status.
Moreover, to improve the performance you can create non-clustered index on the City column for instance.
Please don't fill your database with lots of rows which are default values.
so you don't store availability of a meeting room, you store booking of a meeting room.
primary key of booking table is date and room id , other fields are who booked this room, when booking was asked, a booking id...
If it is possible to book meeting room for part of the day then primary key should be start_date and room id, end date is stored in another field of the table.

maintaining a price table changes every day

state (st_id,st_name)
district (d_id,d_name,st_id[FK])
product (pid,pnme)
price (max_price,min_price,pid[FK],d_id[FK])
1.)This is my table structure, i want to show the price of products in 5 states and its districts,but in price tbl i'm repeating the product(more than 10) for each district.
Whats wrong with my price tbl, Could you plz give an idea to normalize it..
2.) NOw i'm just planning to add date stamp(start date) field to price tbl so that i can maintain historical price list, but how can i do it without repeating product(like shown below) on each date..any better solution to reduce the tbl rows
_______________________________________
product| price |district|date(mm/dd/yy)|
_______|_______|________|______________|
fan 200 delhi 3/15/2013
speaker 400 delhi 3/15/2013
fan 210 chenni 3/15/2013
speaker 403 chenni 3/15/2013
fan 200 delhi 3/16/2013
fan 210 chenni 3/16/2013
1) There's nothing much wrong with your table design - however, the sample data doesn't make sense, as there's a repeat for product 1 and district 111. You might want to create a composite primary key on pid and d_id.
2) Again, nothing much wrong with the table design; you might consider only entering data if there's a change, so that retrieving the price for a given date searches for the last record before the desired data. That reduces the size of the table.
General points: please pick a naming convention and stick to it - you use pid and d_id (one with an underscore, one without); in general, I prefer more descriptive column names, but consistency is key.
Also, there's nothing wrong with large tables, as long as the data isn't redundant. Your design seems to have no redundancies.
1.)This is my table structure, i want to show the price of products in 5
states and its districts,but in price tbl i'm repeating the product(more than 10)
for each district.
If you're offering all your products in all those districts, and the price varies depending on which district the product is sold in, then it only makes sense that you'd repeat the product for each district.
Whats wrong with my price tbl, Could you plz give an idea to normalize it..
It looks like your price table doesn't have a sensible primary key.
If you'd built the table along these lines . . .
create table prices (
district_id integer not null references districts (district_id),
product_id integer not null references products (product_id),
primary key (district_id, product_id),
min_price numeric(14,2) not null,
max_price numeric(14,2) not null
);
you'd have a table in 5NF, assuming that minimum and maximum product prices vary among the districts. But your sample data couldn't possibly fit in it.
1) In your Price (Price Range) table, I don't understand why (d_id, pid) repeats? There should be only one price range, unless you put an effective date column in the table.
2) You could have a future price table, a current price table, and a history price table. This allows you to enter price changes in advance, keeps the current price table short and allows you to get the historical prices infrequently when you need them. Your application code maintains the relationship between these price tables.
I'm not sure where city came from in your other Price table, since you defined state and district.

MySQL - Best performance between 2 solutions

I need and advice about MySQL.
I have a user table that have id, nickname, numDVD, money and table DVD that have idDVD, idUser, LinkPath, counter.
Now I belive that I could have max. 20 user and each user has about 30 DVD.
So when I insert a DVD I should have idDVD(auto-Increment), idUser (same idUser of User table), LinkPath (generic String), and counter that it is a number from 1 to 30 (unique number) (depends from number or DVD) for each user.
The problem is handle the last column "counter", because I would select for example 2 3 random DVD from 1 to 30 that have the same UserId.
So I was thinking if it's the best solution in my case and hard to handle (for me I never used MySQL) OR it's better create 20 tables (1 for each user) that contains the ID and DVDname etc.
Thanks
Don't create 20 tables! That'd be way overkill, and what if you needed to add more users in the future ? It'd be practically impossible to maintain and update reliably.
A better way would be like:
Table users
-> idUser
-> other user specific data
Table dvd
-> idDvd
-> DVDname
-> LinkPath
-> other dvd specific data (no user data here)
Table usersDvds
-> idUser
-> idDvd
This way, it's no problem if one or more users has the same DVD, as it's just another entry in the usersDvds table - the idDvd value would be the same, but idUser woudl be different. And to count how many DVDs a user has, just do a SELECT count(*) FROM usersDvds WHERE userId = 1
You don't need a table per user, and doing so will make the subsequent SQL programming basically impossible. However with these data volumes practically nothing you do is going to cause or relieve bottlenecks. Very probably the entire database will fit into memory so access via any schema will be practically instantenous.
If I understand your requirements clearly, you should be able to accomplish that by creating a compound index for you to be able to select efficiently.
If there is too much of data that is being handled in that table, then it would help to clear up some historical data.

How should I store types of coupons in my db?

I'm creating a coupon system with many different types of coupons. I'd like to structure it so it can be extended. I'm not sure the best way to store the different types of coupons, for example:
Fixed amount off entire order
Fixed precentage off entire order
Fixed amount off one item (could be by sku of item or could be most expensive item)
Fixed percent off one item (could be by sku of item or could be most expensive item)
Buy x get y
Free product (by sku of item, by price)
x for $y (3 for $2, 10 for $15, etc.)
I'm using mysql, would it best to store as an array? json? Any other ideas or people with similar issues care to share how they did it?
Off of the top of my head you could have tables designed as follows:
Table: Coupon_Summary
Columns: Coupon_ID(primary key), Coupon_Name
This table will hold 'top-level' data about the Coupon.
Table: Coupon_Description
Columns: Coupon_ID(foreign key), Coupon_Description
This table will hold the description of the coupon.
Table: Coupon_Value
Columns: Coupon_ID(foreign key), Coupon_Value, Coupon_Currancy
This table will hold how much discount the coupon offers. Coupon_Value can be a percentage or a hard value(percentage will be appended with a % sign), if this is zero the coupon offers full discount, or the item is free in other words. This also includes the currency to base the discount amount off of, so that you can do conversions between currencies.
Table: Coupon_Target_Order
Columns: Coupon_ID(foreign key), Order_IDs
This table holds data related to which Order the coupon effects. If the Order_ID is null or zero, the coupon is valid for all orders. Otherwise you can have multiple IDs for multiple orders.
I hope this was of some help =).
I would create another table - tblCouponType for instance and populate it with a unique numerical and string for notes of the types I have, and add to it as new types become available. Then add another column to your coupon table that references the numerical value of your coupon type. This helps with the whole -"Relational" part of the database:)
I assume you have some sort of products table that contains all products you can sell. You can create a coupons table that looks something like:
id discount discount_percentage
INT PK DECIMAL(10,2) DECIMAL(3,2)
1 5.00 NULL
2 NULL 10.00
Then you could create a link table coupons_products like this:
coupon_id required_product_id
INT FK INT FK
1 4773
1 993
So in this example, coupon ID 1 gives a $5.00 discount and requires two products to be present on the order: 4773 and 993. Coupon ID 2 gives a 10% discount and requires no products.
With SomeSQL, I'd rather not use JSON for it is nearly impossible to efficiently query it.
My Approach would Be, simplistically speaking, to have one Table for Coupon types (columns: id, name, ...) and another one for The actual coupons.
In The coupon Table, I would have a column "type_id" Cross-referencing to The "couponTypes" Table (or a Foreign Key, for that matter).
This way, you can always add new Coupon types later on without invalidating The Data you had to this Point.
Querying "Coupons by Type" is a matter of
"SELECT 'id' FROM couponTypes WHERE 'name' = 'fixed sum'"; => $id
"SELECT * FROM coupons WHERE 'type_id' = $id"; => All fixed sum Coupons.
Welcome to MySQL!