Displaying Products from Mysql PHP - php

RDBMS: MySQL
I'm designing an online store and need some assistance in displaying the products for a category page. Say there are 100 products and each product has 1-3 images.
I need to display all products, but also multiple images per product.
I'm having trouble in finding a way to display it correctly.
Database schema:
I can retrieve the data as an array and loop through it but if I join the tables with all of the images I'm going to have duplicate rows retrieved with different images in each. I'm having trouble understanding how I would display multiple images for every product when viewing all products.
Let me know if you'd like me to elaborate further.
Thanks in advance!

Write two separate queries to fetch data from the database:-
Fetch all the products from the database and then display them to the page
Second query: Fetch the images based on ProductID. If you wanna do something fancy, you can use java script to rotate the images.
Let me know if you need further assistance. Thank you!

You can use group_concat() Mysql function to get all the images in one go, without duplicating the records. Below example shows the same.
select p.product_id, p.product_name, group_concat(pi.image_path)
from procuct p join product_images pi on p.product_id = pi.product_id
group by p.product_id, p.product_name
This will give you all the paths as comma separated list along with each product record.

Use this query:
select products.*,GROUP_CONCAT(image_path)
form products
LEFT JOIN product_images on products.product_id = product_images.product_id
GROUP BY product_images.product_id
You will get the result of products with comma separated images
then explode those comma separated images in PHP and display it.

Related

How to select product with multi level categories in sql?

I am using codeigniter and MySQL to build an ecommerce web application.
This one required three level of categories. So I have created 3 tables. These are-
category
category_id, category_name
subcategory
subcategory_id,subcategory_name,subcategory_category_id
subsubcategory
subsubcategory_id,subsubcategory_name,subsubcategory_subcategory_id
Here they are linked as parent of one another. Finally I have the product table
product
product_id, product_name, product_subsubcategory_id
Now, I need a sql query on this to fetch all product of any specific category.
Something like
$this->Mdl_data->select_products_by_category($category_id);
Please help me on this. I have tried PHP programming to solve this. But it was too slow with lot's of nested loops.
If you need to select all products, that match some specific category, try this request:
SELECT p.product_id, p.product_name, p.subsubcategory_id FROM category c
JOIN subcategory sc ON sc.subcategory_category_id = c.category_id
JOIN subsubcategory ssc ON ssc.subsubcategory_subcategory_id = sc.subcategory_id
JOIN product p ON p.subsubcategory_id = ssc.subsubcategory_id
WHERE c.category_id = 1;
But you should think about changing your database structure to make your requests faster and simpler.
Edit: Answering the comment about how to improve DB.
Current design of database looks correct, according to actual data relations. 1-many for cat-subcat and 1-many for subcat-subsubcat. But this leads to complicated (and possibly slow) queries while usage.
One way I see is to implement many-many relation with additional restriction. You can create additional table cat-subcat, just as you would do if you needed many-many. But in that table you can set unique limitation to subcat_id, so every subcat could belong only to 1 cat and it becomes in fact 1-many relation. But in this case you can move both up- and downwards the hierarchy. This approach will reduce number of JOINs in your query only by 1, but the whole logic of the query would be easier to understand.
Another way. As I understand this is the query for web-store filter. So, new products will be inserted much more seldom, than viewed by category. You can just add subcat_id and cat_id fields to your product, which is not good idea from the point of data structure, but for this particular situation this might be good solution. Every time new product is inserted to DB, you should control the correctness of those 2 fields by PHP or whatever you use on server. But when products are searched by category you will have simple request without JOINs at all.
Both approaches are based on the idea to sacrifice some space for speeding up and simplifying the queries, that are frequently used. Maybe there is even better solution, but I can't find it right now.

PHP - Mysql how show items from a DB related to specific column

Hello below some info about my problem
My_DB name is: products
Table name is: spec_products
Columns in spec_products are:
id|sku|brand|title|price
How can i show (with php) only items from the brand column?
In particular it's a piece of code that i need insert in sidebar of single product page that show products correlated to the brand
Here is the MySQL query:
Select brand From spec_products;
use clause distinct to avoid duplicate values if more of one of your products have the same brand
select dintinct brand from spec_products
From what I understand, you want to display only the brands from the table. If this is the case, it is a simple Selecting Data from MySQL that you would have got by simple search on Google.
You can refer to a W3School tutorial here
You can simply run a SELECT query for brands:
SELECT brand FROM spec_products

Mysql join or php in_array() which is better to optimize Mysql query?

I am trying to implement a watch-list functionality to my current project,in which users can add items to their watchlist.
So up to adding the items to watch list works fine but when displaying all items(that in watchlist and not in watchlist collectively) in a particular category,I need to check whether the item in the users watchlist or not and if it is not in watchlist i have to show a button to add to watch list.....if it is already in watch list a button to remove it.
So here I had following tables
watch-list table
item-id(int)
username
date-added (to watch list)
items table
item-id(int)
item-name
item-description
date-added
users table
username
fname
lname
joinDate
At present when a user visits items page there are number of mysql queries
1 query for user check(if logged in get username at the top of the page)
1 query for showing articles(using category filters)
Many queries to show whether an item is in watch list.
I am using a query inside a loop which checks for username and item-id pair from watchlist table and grab the item-id compares that with present article and desides whether it is in watch list (I know it is a bad way ...but I used that for a start as I am a beginner)
If there are 20 items displaying per page there will be 20 queries if 30 items 30 querys and so on....So I just started to figure out ways to optimize it.
One way that I was thinking to implement is to grab the all the item-id in the watch-list table with one query to an array and check using php in_array() before printing the items to the page and print appropriately
I think this works fine for now.But as I am a beginner I want to learn best practices to optimize queriesIs this good to go or can some of you suggest other techniques.
Some of you may suggest to use joins .......but I don't know how to use them in this scenario.If it is a better way ....can some one explain me how to use joins in this scenario
Thanks in advance
Shrikanth
Your thoughts are right, and it would be better to use a join, as this might save you the additional queries for each item.
What you have to do now: Use a left join to determine if the entry is watchlisted. (if it is NOT, the right handed result of the join will be null.
It would look like this (untested):
Selects all Watchlisted items for current user.
SELECT
i.*
FROM
items i
LEFT JOIN
watch-list wl
ON
i.item-id = wl.item-id AND
wl.user-id = {$currentUserId}
WHERE
NOT isnull(wl.item-id) --if theres a right side, its watchlisted
Vice Versa, selects all NOT watchlisted
SELECT
i.*
FROM
items i
LEFT JOIN
watch-list wl
ON
i.item-id = wl.item-id AND
wl.user-id = {$currentUserId}
WHERE
isnull(wl.item-id)
Selects ALL items and inserts a flag to determine wheter the item is watchlisted or not.
SELECT
i.*,
IFNULL(wl.item-id, "0") as watchlisted -- will be > 0 if watchlisted.
FROM
items i
LEFT JOIN
watch-list wl
ON
i.item-id = wl.item-id AND
wl.user-id = {$currentUserId}

Temporary Table and Left Joins not showing results as expected

I'm really hoping someone can help me with this. I have a number of product attribute types that users can select from to refine the products that are returned to them on screen. What I'm trying to do is, for each product attribute type, I want to list all attributes that relate to either the selected category or search term, then once they've made their selections, I still want to display each of the attributes that relate to the category or search term, but only display a clickable link if the product count for that particular attribute is greater than 1 and for those that have a product count of zero, I want to list them, but make them unclickable. An example of what I'm trying to achieve can be found on the ASOS website, in the left hand menu
http://www.asos.com/Women/Dresses/Cat/pgecategory.aspx?cid=8799#state=Rf961%3D3340%2C3341%40Rf-200%3D20&parentID=Rf-300&pge=0&pgeSize=20&sort=-1
Initially I tried using just joins to achieve this, but I wasn't able to do it, successfully. So I decided to create a temporary table for each attribute type which held a list of all the attributes that related to the main query and then created a refined query, with a left join. Here's my code:
CREATE TEMPORARY TABLE temp_table
SELECT su_types.id, type AS item FROM su_types
INNER JOIN su_typerefs ON su_types.id=su_typerefs.id
INNER JOIN su_pref ON su_typerefs.mykey = su_pref.mykey
WHERE wp_category_id =40 GROUP BY su_typerefs.id
$sudb->query($query);
if ($sudb->affected_rows > 0) {
SELECT temp_table.id,item,COUNT(su_typerefs.mykey) AS product_count FROM temp_table
LEFT JOIN su_typerefs ON temp_table.id=su_typerefs.id
LEFT JOIN su_pref ON su_typerefs.mykey = su_pref.mykey
LEFT JOIN su_stylerefs ON su_pref.mykey = su_stylerefs.mykey
LEFT JOIN su_productrefs ON su_pref.mykey = su_productrefs.mykey
WHERE wp_category_id =40 AND su_stylerefs.id in (91) AND su_productrefs.id in (54) AND su_typerefs.id in (159) GROUP BY su_typerefs.id
if ($itemresults = $sudb->query($query)) {
while($itemresult = $itemresults->fetch_array(MYSQLI_ASSOC)) {
$id=$itemresult['id'];
$item=$itemresult['item'];
$product_count=$itemresult['product_count'];
build_link($list_type, $item, $product_count, $id);
}
}
In the above example the first query selects all the product types that relate to a particular category, say dresses. And the second query is based on the refinements the user has made on the category, in this example this is product, product type and style. A user can also refine their search by colour, fit, fabric and design.
There are a couple of issues with this:
1) The number of results returned in the second query do not match the results of the first. Using the above as an example, I wish to list all products that relate to the chosen category, then using the second query return the product count for each of these products as I described above. So if the temporary table returns, trousers, jeans and skirts. I expected these three items to be displayed on screen based on the conditions applied in the second query, however my results may only show trousers and jeans, if there is not a match for skirts in the second query. I thought that using a left join would mean that all the results of the temporary table would be displayed.
2)Also I wonder if I'm doing this the most efficient way. I have a total of 8 attribute groups, and therefore need to do the above 8 times. If the user choses to refine the results using all 8 attribute groups then in addition to the temp table join, there will be a total of 9 joins for each type. It's taking a while to execute, is there a better way to do this? There are approximately 1/2 million products in the table, and this will probably be 5 times this, once my site goes live.
I really hope all that I have written makes sense and I'd really appreciate the stackoverflow community's help with this, if anyone can help. I apologise for the essay ;). Thanks in advance
To answer your first question; yes, a LEFT JOIN will indeed keep all data from the initial table. That, however, isn't the problem.
The reason why you lose empty categories, is most likely (I say this because I don't fully know your db structure) because of the where condition filtering out all results based on the data in the joined tables.
If for a category all items get filtered out (possibly including the NULL joined values), you will not get this category back from that query anymore. Also the GROUP BY is done on a joined column, that might also effectively wipe out your other categories.
As for the second question, you already state it's taking long; so it's probably not the way to go if you want things to work fast ;) (okay, obvious answer, low hanging fruit, etc). What you might want to do, is get a collection of keys from the filterable categories first, and use that data to select items.
This prevents that you have to join up your entire products table in a temp table (at least, that's what I think you're doing), which of course will take long with the given number of entries. Selecting a list of matching IDs from the given attributes also gives you the advance of using your indexes (more), which a temp-table probably won't have. If this is possible and feasible mainly depends on your schema's structure; but I hope it might lead you to the direction you want to go :)

Multiple Queries on Same field in tables

Really hope someone can help me or at least point me in the right direction. I working on a product site, that allows visitors to filter their results using a menu on side of the product results, similar to what www.asos.com have done. Basically, they can chose product type, style,price,fit ... etc. Each of these fiter types, have their own table and a reference table which links each value to the products table. EG There is a
Products table with productkey and all other product information
Colours table, with the following fields, Colour_ID, Name
Colourref table with productkey, Colour_ID
I'm using MySQL and PHP. I know how to query the database and display the data if the visitor makes one selection from each filter type and then to display the counts for each attribute, but I'd really like to be able to allow them to make multiple selections and then calculate the counts for each attribute, based on what's been selected. I've looked into how this should be done, and I've seen that subqueries are an option, but I'm concerned about how many subqueries I would need to create as I have 9 filter groups, that can have a large number of values. There are currently, 1/2 million products in the database, and this grow over time. I'm capturing the values that need to be queried via the url, so as an example
page=1&view=20&product=125,137,147&type=1,3,5&colour=3,9,5&material=187,345
As you can see from the example, I can have multiple values for each time. I tried writing a query using AND. Example, product = 125 AND product = 137, but that doesn't work.
Does anyone have any advice on the best way to go about doing this even if it's just a point in the right direction?
Any help will be greatly appreciated
Thank you in Advance
Vivien
Basically you answered your own question already:
SELECT ...
FROM ...
WHERE (product = 125 OR product = 137) AND
(colour = 3 OR colour = 8 OR colour = 5) ...
You need to use OR instead of AND if you want to select several products, colours and so on.
If you want both a product and colour then you need to combine those using AND in between. There is no need for subqueries here.
It's easier to use IN though:
SELECT ...
FROM ...
WHERE product IN (125, 137, 147) AND colour IN (3, 5, 8)
A more complete example of this SQL code:
SELECT p.*
FROM Products p
LEFT JOIN Colourref cr
ON cr.productkey = p.productkey
LEFT JOIN Colours c
ON c.Colour_ID = cr.Colour_ID
WHERE
p.productkey IN (1, 2, 4)
AND c.Colour_ID IN (1, 2)
This will select all products that have the ID 1, 2 or 4 which have the colours 1 or 2.
It left joins the required tables on the IDs and then filters the desired values.

Categories