If I have two tables with their respective columns:
=====================
product_categories
=====================
id | name
=====================
=======================
products
=======================
id | category_id | name
=======================
And I have the following PHP functions:
// Returns an array of all rows from the products
function getProducts() { ... }
// returns the corresponding row to the given id of the product category
function getProductCategory($category_id) { ... }
Currently, I am displaying a list of all products in a table with the following headings:
id
Category
Name
Where category is the name of the category corresponding to the category_id of the product.
Currently I am using a foreach loop to iterate through the product and calling the getProductCategory(...) function for each product:
<?php
...
$products = getProducts();
foreach ($products as $product) {
$product_category = getProductCategory($product['category_id']);
...
}
...
?>
Which would be an extensive amount of queries to the database if there are lots of products with many repeated queries.
Would it be good practice if the getProducts() function include all it's category information using a JOIN in the SQL statement?
If you want to get id, category_name and product_name each time, you should make ONE method and avoid to make one select, then a foreach on each product and an other select to get all value.
So try something like this maybe :
function getProductsData() {
$querie = 'SELECT
p.id, p.name,
pc.name as Category
FROM products as p
LEFT JOIN product_categories as pc on pc.id = p.category_id
ORDER BY p.name; -- optionnal
';
// Get the data and return them
// You should get an array with one row =
// id (of the product) / name (of the product) / Category (the name of the category)
}
Yes, Join will be better. It will reduce the number of queries for fetching the category. Otherwise, you can do the separate query for getting the categories as below code, but I will suggest Join.
$products = getProducts();
$categoryIds = [];
foreach ($products as $product) {
$categoryIds[] = $product['category_id'];
...
}
$product_category = getProductCategory($categoryIds);
You have to modify the query in getProductCategory() and add where in condition for comparing category ID
In getProductCategory(), you can implode the category IDs, for adding it into the where in clause.
Related
I have in my MySqli Database a table called "products".
Products TABLE
product_id | INT primary KEY
product_name | VARCHAR(50)
product_price | float
From PHP i enter rows in the table products like this way:
mysqli_query($con,"INSERT INTO products (product_id,product_name,product_price) VALUES
('$product_id','$product_name','$price')");
So far all work perfectly. Now i want to have a second table called "category", this table will include all the possible categories that a product can have
The Category table must have a category_id and a category_name as columns
Category TABLE
category_id | INT primary KEY
category_name | VARCHAR(50)
I'm trying to figured out a way to connect a product with the category in my PHP file
for example:
$get=mysqli_query($con, "SELECT * FROM `category`");
while ($row = mysqli_fetch_assoc($get)) {
echo $row['category_name']; //...here show all the categories
//...
//.. pick the category that the product belong
$category_Selected= .....;
}?>
..... And make the connection (with INSERT? or something) between product and category
Ι want to be able when i'm doing a search at the product table, (for a product X) to show also and the category that it belongs (so far i can show the Product_id, product_name and product_price)
Thank you
You want to join your Tables.
Take a look here:
Join Tables - w3schools
MySQL Join Tables Syntax
If a product can be only in one category then you can add a category_id in your Products table.
I would suggest a third table the:
Product_category
id | PK
product_id | Foreign key to Products.id
category_id| Foreign key to Categories.id
Now every time you insert a product you need to get also the id of your category and do an insert statement to Product_category table.
To retrieve your data you could do something like this:
$get=mysqli_query($con, "SELECT * FROM `category`");
while ($row = mysqli_fetch_assoc($get)) {
echo $row['category_name']; //...here show all the categories
$products=mysqli_query($con, "SELECT * FROM `Products` WHERE id IN
(SELECT product_id from Product_category WHERE category_id= ".(int)$row['category_id'] . ")");
while ($product = mysqli_fetch_assoc($products)) {
echo $product["product_name"] . ", " . $product["product_price"];
}
}
The above statement is as example, you could use JOIN and prepared statements.
If you choose to alter the product table and add the category_id there, then
the example code would be this:
$get=mysqli_query($con, "SELECT * FROM `category`");
while ($row = mysqli_fetch_assoc($get)) {
echo $row['category_name']; //...here show all the categories
$products=mysqli_query($con, "SELECT * FROM `Products` WHERE category_id = " . (int) $row["category_id"]);
while ($product = mysqli_fetch_assoc($products)) {
echo $product["product_name"] . ", " . $product["product_price"];
}
}
As it is, your database does not allow you to represent the relationshup between categories and products. You would need to alter your design.
I can imagine that one product belongs to a category, and that one category can have several products.
If so, I would recommend creating a categories table to store the categories, with (at least) columns category_id and category_name.
CREATE TABLE categories (
category_id INT PRIMARY KEY AUTO_INCREMENT,
category_name VARCHAR(100)
);
In the product table, you want to add a column in the products table that stores a reference to the id of the corresponding category :
ALTER TABLE products ADD
COLUMN category_id INT
FOREIGN KEY (category_fk) REFERENCES categories(id) ON DELETE CASCADE;
With this modified database design, when you insert into products, you pass the reference of the category (one could expect that the user of your application will select it from some kind of drop down list when creating the product) :
INSERT INTO products (product_id, product_name, product_price, category_id)
VALUES ( :product_id, :product_name, :price, :category_id );
And when you want to display a product along with its category name, you can use a simple JOIN :
SELECT p.*, c.category_name
FROM products p
INNER JOIN categories c ON c.category_id = p.category_id
WHERE p.produt_id = :product_id
PS : never pass POSTed values to your SQL queries like this : this exposes you to SQL injection (and also makes your queries less readable and efficient). I changed the queries to use named parameters.
I have 3 tables, Order, Products, Order_Products. I need get all field from order and products, thats ok using hasManyThrough(). But i need 1 more field from Order_products. How can i get this field ?
public function products()
{
//in order model
return $this->hasManyThrough('App\Models\Product','App\Models\OrderProduct','order_id','id','id','product_id');
}
using sql i need query like
SELECT
products.*, order_products.order_id, order_products.count as order_count
FROM
products
INNER JOIN order_products ON order_products.product_id = products.id
WHERE
order_products.order_id = 2
You can access intermediate table fields by using pivot attribute on model.
Lets say you have product, Then you can access count field of orders_products
$product->pivot->count;
Let's say I have the following table, called test:
Executing the query SELECT DISTINCT category FROM test ORDER BY category; will output:
When changing a value as follows:
…and calling the query SELECT DISTINCT category FROM test ORDER BY category; again, I'll get:
But I want to get the following instead:
Is there a way to do this in SQL? Or should I do this directly in my PHP?
You should have 3 tables here. One will hold the the categories, the other one will hold the items and the final one will hold the relations between categories and items (it is also known as associative table):
categories: id name
items: id name
categories_items: category_id item_id
Your query in this case will become:
SELECT id, name
FROM categories
ORDER BY name;
If you want to get all items from a category you could do:
SELECT id, name
FROM items
JOIN categories_items
ON items.id = categories_items.item_id
AND categories_items.category_id = 4;
You should definetely normalize your tables but if you still insist on this table structure, you can try this query:
WITH CatChar(aChar, remain) AS (
SELECT LEFT(category,1), RIGHT(category, LEN(category)-1)
FROM test WHERE LEN(category)>0
UNION ALL
SELECT LEFT(remain,1), RIGHT(remain, LEN(remain)-1) FROM CatChar
WHERE LEN(remain)>0
)
SELECT DISTINCT aChar FROM CatChar
(Assuming your all category names are just one char length, otherwise you should reorganeze LEFT(...) part to split according to your separator)
Hi everyone this is my first question here and i'll be very grateful if you could help me.
I have a table like this in mysql
//table items
id | item_name | description | link | category_id | is_active
And i have another table like this
//table categories
id category_name | cat_description | is_active
I want to get all the data in category_name and get all the content from item_name if is_active column is on, and also if category is_active column is on.
I was trying to make a function that would retrieve all that data with html content and just if certain conditions are true.
My function is something like this:
function getCatAndItems(){
include "conn.php";
$petition = mysqli_query($conn,"SELECT * FROM items,categories WHERE is_active=1");
while ($row = mysqli_fetch_array($petition)) {
$filename = $row['nombre'];
$url = $row['url_document'];
echo "<a href=../docs/files/$url'><li> ".$filename."</li></a>";
}
}
My goal is to bring the categories and if the categories are active and if the items table in the category_id is the same as the category id and is_active it will bring me also the data in the items table that share the same number.
I hope you understand me and hope you could help me, thank's
You can get using JOIN
SELECT items.name, items.description, items.link, categories.category_name, categories.cat_description
FROM categories
JOIN items
ON categories.id = items.category_id
WHERE categories.is_active = 1
AND items.is_active = 1;
Here is your query :
select i.id,i.item_name,i.description,i.link,i.category_id,i.is_active,c.category_name
from items as i left join categories as c on i.category_id=c.id where
i.is_active=1 and c.is_active=1;
A simple inner join between these two tables would do the job done.
SELECT
items.name,
items.description,
items.link,
categories.category_name,
categories.cat_description
FROM categories
INNER JOIN items ON categories.id = items.category_id
WHERE categories.is_active = 1
AND items.is_active = 1
Doing an allnighter on a project and my mind is blank atm... Simple question really:
I have two MySQL tables, product and category. Each product belongs to exactly one category. Every category has several products.
SELECT
p.uid as product_uid, p.name_NL as product_name, p.price as product_price,
c.uid as category_uid, c.name_NL as category_name
FROM
product p, category c
WHERE
p.category_uid = c.uid
This gives me a nice overview of all products in their respective category. My question is about outputting this data on the page. I'm aiming for this:
<h1>Category name</h1>
<p>Product in this category</p>
<p>Other product in this category</p>
<h1>Next category</h1>
<p>Product in next category</p>
My mind is completely blank right now. How would one go about doing this?
I would like to avoid doing subqueries (if possible).
Kind regards,
M
What about adding ORDER BY category_uid so that the products are ordered by category in your SQL query. Then using PHP, loop through each product (row) and when you encounter a new category, add a new header.
Example:
<?php
// ...
$previous_category_uid = null;
// Loop through each row.
while ( $row = $result->fetch_assoc() )
{
// If the category UID is not the same as the one from the previous row, add a header.
if ( $previous_category_uid != $row['category_uid'] )
{
echo '<h1>' . $row['category_name'] . '</h1>';
$previous_category_uid = $row['category_uid'];
}
}
The benefit of this method is that you don't have to nest queries. A single query will suffice.
Don't you just need to use a GROUP BY category_uid ?
Generally speaking you have two options:
Get all the data at once (like you are doing currently) then use PHP to either pre-sort the data by category. Then do your output looping over this array. So 1 query, 2 + n loops (where n is the number of categories).
Get all your categories and then loop over those for output. In each iteration you will need to query all products for that loop. So 1 + n queries, 1 + n loops (where, again, n is the number of categories).
Option 2 might be more straightforward, but clearly there are more queries. In the end, it's your call.
Assuming you're looking for alphabetical ordering for category names and products within each category:
SELECT
p.uid as product_uid, p.name_NL as product_name, p.price as product_price,
c.uid as category_uid, c.name_NL as category_name
FROM product p INNER JOIN category c ON p.category_uid = c.uid
ORDER BY category_name, product_name
This also converts your query's Cartesian product and WHERE to an inner join.
To output with the headers you want, just loop over the returned rows, and keep track of the category you're in. Whenever the category of the current row is different from the previous one, you print a new h1 for the new category and update the stored "current" category.