I am currently creating a custom e-commerce site (in php, but that's not really relevant for this question).
I have just got to creating the shopping basket, and cannot decide between the following 2 options:
option 1:
Basket table:
id
user
items
In this option, I would have one row per user, with all of the items and quantities stored in the items field.
This format is already used in the cookie based basket for non-logged in users, so parsing of the items field is no problem.
option 2:
Basket_items table:
id
user
item
quantity
In this option, I would have one row per item in the basket.
option 3:
suggest a better idea.
conclusion
Both of these options are equally easy for me to implement, so the question comes down which would be more efficient/convenient for updating the basket.
Thank you for any answers, Nico
Option 2 is the way to go. Storing all items and quantities in items field (option 1) means you are going against the relational nature of MySQL. You'll have to define a format and parse it with option 1, additional code you don't have write with option 2. Also, with Option 2, you'll be able to do other things easier down the line, like calculate totals, shipping amounts, etc, as well as reporting on item quanities sold (just a simple query).
Of course, if I was writing this, I'd also ask myself if there is a library available to do this - why reinvent such common a functionality as shopping cart. I am not from PHP world, so I don't know what the options are, but I am sure there must be something you can reuse. So ultimately, I'd encourage you to choose option 3 - don't implement it yourself if you an avoid it :-)
Use Option 2 - you can't realistically support changes to a shopping cart using Option 1, or report from it.
OPTION 3
You will need, at a minimum, a basket table and a basket_items table. Shopping carts become inherently bloated and you will soon realize you're going to need more relation tables than you anticipated. Breaking the tables up in this manner provides a 1-to-many relationship for each user's basket to their items.
This will let you do things in the future like apply promotional codes to each user's basket.
basket
id
user_id
basket_items
id
basket_id
item_id
quantity
Option 1 would require you to serialize the data in the items column which is generally frowned upon for complexity and performance reasons.
You're using a DB for its linking capabilities so lets use them. Your cart_items table should work out really nicely. This way each cart can point to a user and all the items in the cart can point to the cart.
Option 2. This is the best option and provides good data normalisation. It will give way for possible future advanced selects and filtering of the users basket.
Options 2 is the preferred option.
"item_id" could be a id to a table where all items are stored (Store table) and where the complete description and other information is available for this item. But I would add a price tag to this basket for each item and often it makes sense, to add also the users session id /md5 hash to this basket. So the SQL query string for PHP to create such table, could be something like:
$sql="CREATE TABLE ".$table_prefix."Basket (
id int(11) NOT NULL auto_increment,
sid varchar(50) default NULL,
item_id int(10) default NULL,
quantity int(10) default 1,
price varchar(10) default NULL,
PRIMARY KEY(id)
) $collate_charset;";
$collate_charset: something like $collate_charset="DEFAULT CHARACTER SET utf8";
$table_prefix: often useful to have a prefix for the tables like $table_prefix="myshop_";
With such table you can benefit from SQL functions like "Sum" to get a quick subtotal of a user or all users without much code ("Select Sum(price * quantity) WHERE sid = '1234'").
If this basket is also for "guests", you need another table where the session-id and creation date is stored, so you can regularly cleanup the basket from unused entries.
Related
I am making a site that has many services to buy, my problem is to find the best way to make an ERD for this structure!
as I show an image I have a routine system for making a contract for a user, in another word I have a simple table to insert a contract and its related information for user and member.
I store all relation of Contract tables in Junction table. but my problem is that I have many services that have a different price that calculates with its own circumstance( FirstServicePrice, SecoundServicePrice **, **ThirthServicePrice and ...).
I decide to use a junction in name of JunctionForFindPrice for keeping each service primary for a contract. 4 example if someone buys the first service I keep just FirstServicePrice ID in JunctionForFindPrice table in FirstServicePriceId field and leave another field null, and then store Id of JunctionForFindPrice in Junction Table (Gray table in Figure).
is it the best Way for this Implementation? is it the correct way?
There are as many pricing schemas as there are applications because everyone does it a little differently, so don't worry: we've all been confused by how to do this the "right" way. One common method is to create a table like [Orders] with fields like [ClientID], [DateOrdered], and [OrderedBy], and another table,[OrderLineItems], that contains each [ServiceID] they add to the order and the price for that service stored as a number ($23.99). Instead of a price junction table, you would have a function or stored procedure that determines the client's price for that service as it's added to the OrderLineItems table.
In my primary application we have a table of "standard prices" for each service with start/stop dates: that allows us to set up price increases in the future. Then we have a table of possible discounts that allow three types of discount, set the new price, discount by x%, or discount by x$. "Discounts" can be negative where we want to charge clients more. This makes for a very flexible pricing structure but the code to figure it all out is very complicated and brittle.
We currently have a SQL database with a table that holds online sales for our company, which sells products using other websites (say, Amazon). The table schema has been set up to hold specific sale data/attributes provided by the website our items are currently sold on (say, Site A).
We are expanding sales to other websites that provide different attributes than Site A uses when an item is sold (e.g. Site A might provide a unique sales id number, and site B might not provide a unique sales id number, but also provide some other info that Site A doesn't provide that we still need to capture).
The question is do I add a separate table for sales on each 'site' that we sell on, as the schema will be different, or try to combine all sales into one table, no matter the platform, leaving some columns null if it doesn't pertain to the particular platform? Or maybe a hybrid approach, separating only the attributes that aren't common among the two sites into separate tables, while a "master" sales table holds attributes that are shared (sale_price, sale_date, etc)?
There are also other tables in play that hold internal information (product Ids, costs, etc), that are linked to the sales table via a unique identifier. Whichever route I choose, I'd need come up with a unique identifier I could use across all tables (auto incremented sale_id, e.g.), and store that in a table for reference/joins.
Any suggestions are welcomed!
A sale is a sale >> same data belongs to the same table. I would definitely not recommend splitting your sales to several tables as this creates lots of difficulty for all that might follow: sales statistics and so on. Try to keep all sales in one table.
If it's a very small project, it might be the best shot to integrate the different fields into one table. Otherwise you might try to create profiles for every sale platform: In this case, use an Entity-Attribute-Value model.
Do not add a table for each site. It sounds like you have a many to many relationship between sites and attributes, so set up your database that way. Also, for any unique identifier you need, create it yourself.
On my site user can make some items and those items goes in Items table.
Users can also follow each other and those data I store in Followings table.
Now I need one table that keep track of user activities, so I have created:
Users{UserId, Username, FirstName, LastName}
Items{ItemId, Title, CreatedByUserId}
Activity{ActivityId, ActivityTypeId, UserId, ItemId}
Here ItemId can be or ItemId from Items table or UserId from Users table.
Is this design good or there is better approach to do this?
Edit: I have added table structures. The point is that I wan't to add record to that Activity table every time when user create item or start to follow some user. So I can always track what user did on the site.
Here ItemId can be or ItemId from Items table or UserId from Users table.
This will prevent the DBMS from enforcing the foreign key. If you go down that route, better separate these fields (so you can make foreign keys towards their respective tables) and use a CHECK to ensure exactly one of them is non-NULL:
CHECK (
(ITEM_ID IS NOT NULL AND FOLLOWED_USER_ID IS NULL)
OR (ITEM_ID IS NULL AND FOLLOWED_USER_ID IS NOT NULL)
)
The ACTIVITY PK is crafted so it is easy to query for a "timeline" of a specific user and is friendly to clustering.
(You may or may not need ACTIVITY.TYPE depending on what exactly you want to track.)
The alternative would be to have a separate table for each kind of activity:
(And you could add a TYPE field in FOLLOW_ACTIVITY to distinguish between "follow" and "unfollow".)
Another alternative would be to inherit users and items from a common parent "class" and then link to that class:
This design is probably an overkill in this case, but could be useful if you later add many other kinds of objects that could be tracked.
Items{ItemID,descr,UserIDCreator,date-time}
User{UserID,descr}
Followings{UserIDFollowed,UserIDFollower,date-time}
now if you wont all items created by eser use user code on items
the same on followings I add date-time for chrono select
You can create atriggered table or a view this depends on cardinality of data
If the same object can be share between users
Items{ItemID,descr,}
UserItems{UserID,descr,ItemId,date-time}
User{UserID,descr}
Followings{UserIDFollowed,UserIDFollower,date-time}
I hope to be useful
I have a doubt regarding a database design, suppose a finance/stock software
in the software, the user will be able to create orders,
those orders may contain company products or third-party products
typical product table:
PRIMARY KEY INT productId
KEY INT productcatId
KEY INT supplierId
VARCHAR(20) name
TEXT description
...
but i also need some more details in the company products like:
INT instock
DATETIME laststockupdate
...
The question is, how should i store the data?
I'm thinking in 2 options:
1 -
Have both company and third-party, products in a single table,
some columns will not be used by third-party products
identify the company products are identified by a supplier id
2 -
Have the company products and third-party in separated tables
3 - [new, thanks RibaldEddie]
Have a single product table,
company products have additional info in a separated table
Thanks in advance!
You didn't mention anything about needing to store separate bits of Vendor information, just that a type of product has extra information. So, you could have one products table and an InHouseProductDetails table that has a productId foreign key back to the products table that stores the company specific information. Then when you run your queries you can join the products table to the details table.
The benefit is that you don't have to have NULLable columns in the products table, so your data is safer from corruption and you don't have to store the products themselves in two separate tables.
Oooo go with 3! 3 is the best!
To be honest, I think the choice of #1 or #2 are completely dependent upon some other factors (I can only thing of 2 at the moment):
How much data is expected (affecting speed of queries)
Is scalability going to be a concern anywhere in the near future (I'd guess within 5 years)
If you did go with a single table for all inventory, then later decided to split them, you can. You suggested a supplier identifier of some sort. List suppliers in a table (your company included) with keys to your inventory. Then it really won't matter.
As far as UNION goes, it's been a while since I've written raw Sql - so I'm not sure if UNION is the correct syntax. However, I do know that you can pull data from multiple tables. Actually just found this: Retrieving Data from Multiple Tables with Sql Joins
I agree with RibaldEddie. Just one thing to add: put a unique constraint on that foreign key in your InHouseProductDetails table. That'll enforce that it's a one-to-one relationship between the two tables, so you don't accidently end up with two InHouseProductDetails records for one product (maybe from some dataload gone awry or something)
Constraints are like defensive driving; they help prevent the unexpected...
I would advice on using point #1. What happens when another supplier comes along? It's also more easy to extend on one product table/produst class.
Take into account the testing of your application also. Having all data in one table raises the possible requirement of testing both the 3rd Party & Company elements of your app for any change to either.
If you're happy that your Unit test would cover this off its not so much of a worry... if you're relying on a human tester then it becomes more of an issue when sizing the impact of changes.
Personally I'd go for the one products table with common details and separate tables for the 3rd party & Company specifics.
one table for products with a foreign key to the Vendor table; include your own company in the Vendor table
the Stock table can then be used to store information about stock levels for any product, not just yours
Note that you need the Stock table anyway, this just make the DB model more company-agnostic - so if you ever need to store stock level information about third-party products, there's no DB change required
I have the following tables:
Cateogories
CategoryID (int) Primary Key
CategoryName (varchar)
Items
ItemID (int) Primary Key
CategoryID (int)
ItemName (varchar)
There is a foreign key constraint on Items.CategoryID. There is a chance that when a new item is created that there will be no category assigned.
Is it better to set Items.CategoryID to allow nulls and deal with the nulls in my code OR better to not allow nulls, set the default CategoryID to 1, and create a dummy record in the Categories table called "Uncategorized" and then deal with that dummy category in my code?
The logically correct way would be for the CategoryID column to be NULL when there is no Category for the item.
If you get trapped by any of the gotchas that are associated with using NULL, then that is most likely a sign that the design hasnt taken account of the fact that items cannot have a category. Fix the design. The NULL will ensure you stick to solving the correct problem.
It depends:
If your items really have no category, then I would allow NULLs, as that is what you have: no CategoryId.
If you want to list all categories, you do not want to display the dummy row, so you would have to ignore that.
If you want to display all items and show the categories, you'd better be aware that there are items without category, so you would use a LEFT JOIN in that case.
If possible, change your application to select a category before actually saving your item.
If you want to treat that Uncategorized category just like the other categories (list them with the other categories, count items assigned to it, select it in lists/dropdowns), then it should get it's own category, and Item.CategoryId should be NOT NULL.
Ideally you'd want to force a category choice before allowing an item to be created. If an item will have no category at any point in the future then you'll need to create a category specifically to deal with that. I personally wouldn't call it "Uncategorized" though as this implies that a user can just chase it up later - which they will forget to do with alarming regularity!
Go for logical consistency or you'll end up in a mess. If that means creating a "Miscellaneous" category then do that and make sure that (a) Users know when to use it and (b) It is reported on regularly to make sure items are categorised correctly.
For simple lookup tables of this type it is almost always better to disallow NULLs and have the unknown value in your lookup table.
Why?
Because the ANSI NULL specifications are inconsistent and very complex. Dealing with nulls greatly increases the likelihood of coding defects, and takes a lot more code to write
Because few developers really understand how NULLs work in all scenarios
Because it simplifies your model and queries nicely. You can join things together nicely with inner joins from either direction with very simple sql.
However, a few cautions:
You may want more than one "dummy" value: one for "unknown" and another for "not assigned". Of course, NULL bundles both into a single value, so you're going above & beyond the minimal standard if you do this.
You will end up sometimes having additional non-key attributes that either must be nullable or carry 'n/a' type values for the dummy rows. For heavily denormalized lookup tables (like warehousing dimensions) you'll probably want nulls allows for these columns because 'n/a' doesn't work well for timestamps, amounts, etc.
If you apply this technique to more than just simple lookup tables it will dramatically complicate your design. Don't do that.
SQL NULLs are tricky, so I think you're better off with a sentinel category.
In this case I believe it's really a matter of personal preference. Either way you'll have to deal with the uncategorized items in your code.
I do not believe that either of the alternatives are very good.
If you choose the NULL approach you will have problems with the gotchas involved in working with NULLs. If you choose to not allow nulls, you will need to handle cases where if you delete a category the item would cascade.
IMO the best design is to have three tables.
Categories
ID
Name
Items
ID
Name
Categories2Items
CategoryID
ItemID
This eliminates the need for NULL (and the gotchas involved) as well as allows you to have uncategorized items, and items which belong to several categories. This design is also in Boyce-Codd Normal form which is always a good thing ..
en.wikipedia.org/wiki/BCNF