views:

658

answers:

4

I have read about REPLACE and INSERT ON DUPLICATE key queries, and while I can see how useful they are, they don't appear to work for my purposes. Perhaps my database design is off from how it should be, but either way I hope I can get this working.

I am trying to mock up an online store to teach myself mysql and php, and I am recording a session id for use in pulling an individual's cart back for an individual visit and attempting to write inventory to the cart where I'm having an issue is in trying to check if the item is in the cart or not. I want each item to be unique per user, however it should not be unique for the entire table, or else this would prevent the multiple users from buying the same item, wouldn't it?

My table so far looks like this:

 | Cart ID(key) | USER_ID(fk) | ItemNum | ItemQTY |

and I essentially want to see if a USER_ID already has > 0 ItemQTY of ItemNum in their cart. If they do I would like itemQTY to update to itemQTY + however many they add, and if not, then insert a new line.

Will I have to query before I write in order to do this?

+1  A: 

You could write a stored procedure and use the stored procedure to handle the inserts.

You will need to learn about writing stored procedures and executing them from PHP.

Also, inside the stored procedure you will need to execute more than one query, but to your application it will look like a single call to the procedure.

HTH.

RibaldEddie
Is it safe to add a user input to a stored procedure in the same way it is to add it to a parameterized query?
Chris Sobolewski
I don't know. Is it unsafe? Do you declare the input variable type in the stored procedure? What if you do declare the type but try to pass in the wrong type? What happens? Are you not validating the input even prior to executing any query? Do any of the mysql php libraries support parameter binding for stored procedures?
RibaldEddie
+2  A: 

For a beginner ... I think it's probably okay to just run the query to check if it's there. Then when you're generally more familiar with php and mysql, start building your knowledge.

Others may disagree, but while learning new languages I like to make things work before I make them "perfect."

rpflo
Ultimately, even on a production system, if find myself doubting that running a quick query then insert or update would really kill my database server in anything other than a wildly popular website (please correct me if I'm wrong). I likely will just do this, but I think it's valuable to at the very least a glimpse of how a pro would do it.
Chris Sobolewski
"Holy crap that took 0.00023 seconds longer!" :)
rpflo
Doing two queries might even be faster than a single insert because the read will have primed the update. The blocks to be updated will already be in various caches.
RibaldEddie
+1  A: 

I think you need a multi-column unique key on CartID and ItemNum:

alter table my_table add unique( CartID, ItemNumber );

Then you can do:

insert into my_table values( 1, 'joe', 12345, 1 ) on duplicate key update ItemQTY = ItemQTY + 1;
Chris J
+1  A: 

Traditional shopping cart software has one cart per user, and that cart is restored each time the user returns. Because you have both a CartID and a UserID, this gives the impression that a user is able to have multiple carts.

Whereas, it may be better to have three tables; Users, Carts & CartItems

Users will need a UserID, Carts will need CartID and something like OwnerID (referencing Users.UserID) , and CartItems will have CartID (referencing Carts.CartID), ItemID and Quantity.

You can even get simpler, since a User will only ever have one Cart, you can ignore the Cart table altogether and replace CartItems.CartID with CartItems.OwnerID (referencing Users.UserID.

I hope this is helpful.

Lachlan McDonald
This was my original instinct... my cardID is honestly a superfluous value which is there simply because I was under the impression that all tables should have a unique primary key. I'm not sure where I got the impression from, but it seems to me that you are saying that a table does not need a unique primary key and can just use a forgien key?
Chris Sobolewski
The foreign key would need a unique index, so it serves the semantic purpose of a primary key. However innodb will create a hidden autoincrementing key to order the data on disk. Thus, sone people recommend creating a surrogate primary key. This can also be useful down the road if you want to store other information about the relationship in another table.
RibaldEddie
Or if you want to allow users to save multiple carts or send carts to other users.
RibaldEddie
One thing you definitely don't want to do is to call a column UserID in one table and OwnerID in another table if they have a foreign key relationship to each other. Semantically the nature of the key relationship makes the two values equivalent when they are the same, which means that you are creating confusion by identifying with different names the same thing. Keep it as UserID in the CartItems table. Even better, your design will be more flexible if you keep the UserID column out of the CartItems table and have the foreign key on the Carts table.
RibaldEddie
RibaldEddie, you're right about `OwnerID`; it really should be UserID across all tables to avoid confusion.If you wish to have a `Carts` table though, I'd prefer to keep the `UserID` in `Carts` rather than the `CartID` is `Users` because to me it says "A cart has a user" as opposed to "each user has a cart". Each to their own.
Lachlan McDonald