Related products algorithm - php

When inserting products in an eshop we often need to link some products (aka related products) to others and the linking must be done both ways, meaning if I link product1 to product2 then product2 must also be linked to product1.
Which is the best practice, using an extra table 'relations' (prodid, related_prodid) or to keep a list of related products in a delimited string in each product's row in the products table?
In either case, we would also need a recursive method to loop through a given array of products and insert/update the tables with the relations, could someone help me out with the algorithm? I will do the PHP coding but I cant think of a good way to do it.

You'd better use an intermediate table related_to(id, product1, product2)
Then, you'll use the code:
function findRelatedProducts($product) {
$relatedProducts = array();
$data = mysql_query("SELECT * FROM related_to WHERE product1='$product' OR product2='$product'");
while ($relation = mysql_fetch_array($data)) {
$relatedProducts[] = $relation['product1'] == $product ? $relation['product2'] : $relation['product1'];
}
return $relatedProducts;
}
Of course, you need to JOIN this table with your product table, but since I don't have much informations about your mysql structure, I'll let you check on this site if you don't know how.

Definitely use the extra table (the string solution is really a bad idea), preferably organizing it so that the product with the lowest primary key is put first in the relation (allows for a bit of optimization); there is no need to duplicate the relationships (i.e. having and at the same time).
As for the recursive method thing, it's not clear where you get the relations' value from.

Related

PHP: MYSQL Row into Array

I have a little problem, hope you can help me... In my mysql table row named size I have:
"XS"=>"11", "S"=>"22", "M"=>"33", "L"=>"44"
I would like to get that out in an array, so I can post it to my select.
$x = mysqli_query($mysql_link, "SELECT * FROM dagenshug_produkt WHERE varenummer = '$produktid'");
while($row = mysqli_fetch_assoc($x)) {
$sizearray = array($row['size']);
print_r($sizearray);
}
This returns:
Array ( [0] => "XS"=>"11", "S"=>"22", "M"=>"33", "L"=>"44" )
But i would like
Array ("XS"=>"11", "S"=>"22", "M"=>"33", "L"=>"44")
Anyone who can help me a little?
The new db design
I post this as an answer, as it will be to loong for a comment.
I will delete it later, as it will not be a real answer to your question.
You need to redesign your database. Please read about relational database design.
One (easy) possibility is to have one table-field per size.
The downside to this design is, that if f.e. one product invents a new size called XMS you're f* and need to rewrite a lot of code.
This is where relational tables come in place. If you have an extra table that saves all the sizes per product, you're fine!
such a sizes-table could look like that:
product_sizes
----------------
id // unique id of this entry (int, auto_incement)
label // 'XS', ...
size // '22',...
product_id // the id of the product it refers to
But all that thoughts depend on your requirements that we don't know.
You asked for the wrong question. As raised in the comments, you need to redesign your database.
You don't necessarily have to develop a universal products variations (colors, sizes, matters, etc.).
Your products are in a table, they all have a unique ID. Good. In another table, store your sizes:
id: integer auto increment (PK)
size_name: 2XS, XS, L, M, L, XL, XXL, 3XL
size_description (for information purpose in the backoffice)
product_type (or product category). Remember that XL is a shirt size, whereas 10 is a shoe size.
The pivot table, which materializes the relation between your products and the sizes:
product_id
size_id
This table may contain relation data, like additional cost (sometimes large sizes are more expansive), etc.
To make it even better, you may store the association size<->product type with another table. It will be necessary in your backoffice to allow some sizes to be applied to appropriate products.
Anyway. Designing a database does not happen in phpMyAdmin. Never. There are specific tools for that, like MySQL Workbench. It will help you have full overview of your database.
You also need to know the difference between a table which represents an entity and and a table which exists for technical reasons (sorry, my vocabulary is a little limited in this case). A pivot table is not en entity, even if it can carry data (for example: the date a user was added to a group).
This is very important to know these basics, they will help you build a strong, secure, efficient and fast database.
I hope to help...
$x = mysqli_query($mysql_link, "SELECT * FROM dagenshug_produkt WHERE varenummer = '$produktid'");
$row = mysqli_fetch_assoc($x);
$arr = explode(",",$row['size']);
$a=array();
foreach($arr as $n) {
$m = explode("=>",$n);
$a[$m[0]]= $m[1];
}
print_r($a);

Get multiple results from db

I'm working on a fairly large project in (object oriented) PHP which includes a webshop where users can buy products and additional licenses and services. Purchasing is a four step process:
Step 1: User chooses a product, and product_id is passed to step 2
Step 2: Fetching and outputting all license types based on product_id, passing product_id on to step 3
Step 3: Fetching and outputting all services based on product_id, in a form with checkboxes named services[$service_id]
So now, on the checkout on step 4, I fetch the correct products and licenses from the database, but I also have to get the correct services from the db based on the services array, and calculate the price to output. At last, I'll have to assign the services array to the Smarty template.
How would the most suitable way to do this be? I really hope that someone is kind enough to help me out here, as I'm having a very hard time trying to make this work.
Thank you so much in advance.
Try using
$resulter = array();
$i = 0;
foreach($product_id as $value) {
$query = "Select FROM products WHERE product_id = $value";
Your execution code
$resulter[$i] = $result; //$result could be a assoc array
$i++
}
And If I ware you I would i would use a multidimensional array like I shown above.
Sounds like you need a JOIN.
Something like a JOIN on the 'products' table and 'licences' table using the 'product_id' field to make the join.
An example query would be something like:
SELECT <required_fields_here>
FROM products
JOIN licences ON licences.product_id = products.product_id
WHERE product_id = <product_id_here>
Note that in the SELECT section you can select fields from both 'products' and 'licences' tables, you just need to prefix with the table and a dot e.g. 'product.product_id'
I think you will need to be more specific if you need further help. Hope it helps.

Should I create a new table into my database for this?

On my database I have among other tables, products. Products table contains the id, name, description and some other data about the product. I want to add also a category.
Should I create a new table named category with and id and the name of each category, and have into the products a *category_id* that will refers to the id of category, or should I have the name of the category on each row of products ?
On the first case I will have to use JOIN. Will this have a serious impact on the performance?
By defining the categories in their own table you can:
Rename categories
Dynamically generate lists of categories for picking from
Add descriptions of categories
Add new categories
… and so on, without having to update every bit of category related code each time you modify them.
So yes, add a table.
Will this have a serious impact on the performance?
Probably not.
Yes you should keep your data normalized. I think create a new table named category is a good idea.
Will categories tend to change over time? In most instances that will be the case, so you're usually better off with a separate Categories table and a foreign key (FK) between the two tables. You can then add or change categories simply with data changes. Otherwise, you'll want to put a check constraint on the category name column in your table to make sure that you don't get junk data in there and that becomes much harder to maintain.
With proper indexing, the join should only have a minimal cost. Also, keep in mind that you won't always necessarily need to join the tables. You'll only need to join them when you want the actual category name as part of your result set. For example, if you have a look-up box on your front end with the categories and their IDs then your select of the Products only needs to return the category ID values and you don't need to even bother with a join.
The stock answer is "it depends". It depends on how the data is used, will be used, might be used. But once you get through all the discussions and arguments, for something this simple and prominent in your data, nine times out of eight you will be better off properly normalizing the data (i.e. Category table, CategoryId columns, and foreign key).
Only add a table if you require the extra functionality this level or normalization provides.
If you need to rename categories, or list them then yes this is a good candidate. If not then why bother with it, it will make your database slightly harder to read.
Join will most probably not be a performance impact but if you do not need it now, try not to be a victim of over-design.

Combining multiple rows or results with the same title to form drop down menus with PHP and MySQL

So I am picking up a project that was quit halfway through by the last guy so that I could get some more practice with PHP and databases. I have run into a problem, and I am sure it is common enough that there is a standard solution, but I am unable to find one.
The db I am working with has 4,600, so reorganizing is out of the question. It is a db of liquers for a wholesaler. Here is what the results page looks like currently:
What I am trying to set it up so the results are returned in list form, with only one title and dropdown menus for the different sizes/prices of products that looks like this:
The problem is that there are multiple entries in the db for each product. In this example there are 3, while some have 1, and some have 2.
I am really not sure how to go about this, and any help would be greatly appreciated. Thank you.
I'm not sure about the PHP syntax, but pseudocode here's what you could do:
allProductsReturnedFromMySQL = QueryYourDatabaseForAllProducts()
Hashtable[productId, List[productSizes]] dropDownsByProduct;
Hashtable[productId, commonProductInformation] uniqueProducts;
foreach (product in allProductsReturnedFromMySQL) {
if product.productId not in uniqueProducts
then add it with the product information that does not vary
if product.productId not in dropDownsByProduct
then add it with an empty list
append the size of this product to the corresponding list in dropDownsByProduct
}
After that little bit of logic you'll have all your unique products with the common properties for each one, and a way to fetch the corresponding sizes drop down. If you wanted to do this purely in SQL to minimize the data that's transferred, you could do something like this:
-- this would get you your products
select distinct id, property1, property2 from product
-- this would get you your drop downs by product
select id, size from product order by id
You can then build the same drop down hashtable by iterating through the second result set.
I'm not sure if this is the best way, but I've always approached this by altering the query so that it is sorted by product name. Then as you iterate through the rows, check to see if the product name matches the one you just processed. If it's the same, then this row is a different size of the same project.

Tricky MySQL Insert and Update

I'm making a shopping cart for my website.
When an user add something into the cart it should insert item_id and quantity into the items column in my DB.
The item column should hold a string like this:
1:5;6:2;13:1
item_id:quantity;item_id:quantity and so on
The insert part I already got, but when the user wants to view the cart, the string needs to be split into an array and fetch the items from another table
Array example:
1 => 5,
6 => 2,
13 = 1
I'v tried using spliti(";" $raw);
But didn't get what I wanted.
And the same thing when the user updates/deletes a product from the cart..
When the user updates/deletes a product, it must search through the string inside items and find the current place of the product.
Any help would be appreciated :)
Since you are building your own cart do it correctly using a properly normalized schema. This means that you need to avoid "special" values which do more than 1 thing at the same time.
So the obvious improvement here is to have:
table users:
id
...
table products:
id
...
table cart_items:
user_id
product_id
quantity
CRUD queries will be very simple to implement then and also very fast.
First off, I don't think it's a good idea to have your items as a string in your order/cart table. You run into a lot of problems this way (you've already run into a couple).
It's better to have a hasMany relationship. Something along the likes of the design shown below is ideal.
Order Table : id, date, total, more, fields
OrderItem Table : id, order_id, item_id, value, more, fields //item_id is a ref to your Items/Product table
This allows you to link your items to your orders properly and you can do your inserts and updates without a problem.
As for your current question, you need to split it twice
$items = 1:5;6:2;13:1;
$items_arr = explode(';', $itemrs);
$new_items = array();
foreach ($iterms_arr as $item) {
$pieces = explode(':', $item);
//might want to do some error checking on whether the indices exist
$new_items[$pieces[0]] = $pieces[1];
}

Categories