I'm very new to MySQL and PHP and I'm struggling with inner joins between two tables. I'm constructing a script that reads an os commerce database and tells me which products is currently on back order. In order for the product to be on back order a value in the products_attributes table is set to '134', however it only reads the product_id and not the product_model which is in the 'products' table.
products_attributes(table name)
options_values_id
product_id
products(table name)
product_id
product_model
I want to select items that have the value of '134' in the products_attributes table then match the product_ids from both tables to get the product_model from the "products" table. I feel like the code is very easy but for some reason I'm struggling with how to construct the query and to display it.
SELECT product_model FROM products as p,products_attributes as pa WHERE p.product_id = pa.product_id and pa.options_values_id = 134
or
SELECT p.product_model FROM products p INNER JOIN products_attributes as pa ON (p.product_id = pa.product_id) WHERE pa.options_values_id = 134
I think that you're asking how to get the product ID of anything have an attribute of 134
In that case, no JOIN is required.
SELECT DISTINCT
product_id
FROM
products_attributes
WHERE
options_values_id = 134
If you want the product_model then you could form the JOIN like this
SELECT DISTINCT
p.[product_model]
FROM
products p
JOIN
product_attributes pa
ON pa.[product_id] = p.[product_id]
WHERE
pa.[options_values_id] = 134
So the JOIN stipulates how the two tables are related to each other. Once there is a valid JOIN you can use the joined table nearly anywhere in the query.
You can try the following:
select p.product_id, p.product_model
from products p
inner join products_attributes pa on pa.product_id = p.product_id
where pa.options_values_id = '134'
Related
i have a problem with making a complicated query easier without the need to build the query with PHP.
My problem:
A product can have several properties eg. a color, a size and a state.
To get a product which has all 3 properties i can:
products p
INNER JOIN product_propeties p1 on p.pid = p1.pid AND p1.property = 1 (color)
INNER JOIN product_propeties p2 on p.pid = p2.pid AND p2.property = 2 (size)
INNER JOIN product_propeties p3 on p.pid = p3.pid AND p3.property = 3 (state)
This works fine. I will get all products which have all this 3 properties.
My problem is now that i dont want to generate p1,p2,p3 with PHP. The properties are listed in a table "property_groups". In this table i can group properties.
proberty|title|group_name
1|color|winterspecial
2|size|winterspecial
3|state|winterspecial
I want to join the "property_groups" table with "winterspecial" and my example from above i dont know how. Problem is that each property needs to exists. Several single joins do the job. But how to do it in a single MySQL Query.
With PHP i select all "winterspecial" and then i build the query with p1,p2...
There must be a better way. Beware that the properties must be AND connectet.
OR is easy this would be a simple subselect.
INNER JOIN product_propeties p1 on p.pid = p1.pid AND product_propeties IN (
SELECT * FROM property_groups WHERE "winterspecial"
)
This may look a bit clumsy, but is the only thing I can come up with at the moment...
In order to know whether a product has all winterspecial properties, we could count all existing winterspecial properties and the product's winterspecial properties and then compare the two numbers.
Then we can select from products and product_properties where the product ID is in the found set:
select ...
from products p
join product_properties pp on pp.pid = p.pid and pp.property in
(select property from property_groups where group_name = 'winterspecial')
where p.pid in
(
select pid
from product_properties
where property in
(select property from property_groups where group_name = 'winterspecial')
group by pid
having count(*) =
(select count(*) from property_groups where group_name = 'winterspecial')
);
Ahhh, I think I get the problem now. You seem to want all products that have the properties in the property_groups table, for a given group.
Here is an approach. Do a cross join to generate the list of products and properties. Then do a left join to match to product_properties. With an aggregation, you can easily tell if all the desired properties match an existing property:
select p.*
from products p cross join
property_groups g left join
product_properties pp
on pp.pid = p.id and pp.property = g.property
where g.group_name = 'winterspecial'
group by p.id
having count(distinct pp.property) = count(distinct g.property)
You can actually simply the having clause to one of these:
having sum(pp.property is null) = 0 -- no null values
having count(pp.property) = count(g.property) -- all match
These should all be equivalent.
I have problem with join left. It work fine but i don't see null results. It connects three tables - categories, product_categories and order_products.
Query made by stack user look's like:
SELECT
categories.name,categories.id,
SUM((orders_products.product_price_gross + orders_products.option_price)*(1 - (orders_products.rebate/100)) * orders_products.product_qty) as suma
FROM orders_products
LEFT JOIN product_categories
ON product_categories.product_id = orders_products.product_id
LEFT JOIN categories
ON product_categories.category_id = categories.id
GROUP BY categories.name, categories.id
ORDER BY suma DESC
I'm not sure how upgrade this query - I need to see what never been sold to show on shop statistics.
I hope You could help me.
Kind regards
Mark
You want to see products that has not been sold? Your main table is the transaction table orders_products. So any product not "ordered" will not show. Interchange product_categories and orders_products to achieve what you want. This will list all categories and null out the "suma" if JOIN statement cannot find the product_id listed in the "order_products" table
SELECT
categories.name,
categories.id,
SUM((orders_products.product_price_gross + orders_products.option_price)*(1 - (orders_products.rebate/100)) * orders_products.product_qty) AS suma
FROM product_categories
LEFT JOIN orders_products
ON product_categories.product_id = orders_products.product_id
LEFT JOIN categories
ON product_categories.category_id = categories.id
GROUP BY categories.name, categories.id
ORDER BY suma DESC
I'm having some problems to get this query works as I expect.
I have three tables: products, product_attributes and attributes.
The relation is obvious (A product can have multiple attributes)
products
---------
id
product_attributes
------------------
product_id
attribute_id
attributes
----------
id
name
What I want to achieve is to get those products that has a given list of attributes, BUT omit those products that only has a partial list of the desired attributes.
For example, having these products and attributes:
Shoe 1 [blue,boy]
Shoe 2 [blue,girl]
Shoe 3 [red,boy]
Shoe 4 [red,girl]
A query asking for those products with [blue,boy] would retrieve only Shoe 1.
A query asking for those products with [blue] would not return anything.
Since now I was working with this query:
SELECT p.*, pa.attribute_id
FROM products AS p
LEFT JOIN product_attributes AS pa ON(pa.product_id=p.id)
WHERE
pa.attribute_id IN(' . implode(',', $attr_ids) . ')
GROUP BY p.id
HAVING count(pa.attribute_id)=' . count($attr_ids)
This fails when just an attribute is given because it will return any product having that attribute.
-- PHP (or any other languaje) parts are hardcoded here!!!!
SELECT p.*, hma.howmuchattr
-- howmuchattr is needed by HAVING clause,
-- you can omit elsewhere (by surrounding SELECT or by programming languaje)
FROM products AS p
LEFT JOIN product_attributes AS pa ON pa.product_id = p.id
LEFT JOIN (
SELECT product_id, count(*) as howmuchattr
FROM product_attributes
GROUP BY product_id
) as hma on p.id = hma.product_id
WHERE
pa.attribute_id IN
(1,3) -- this cames from PHP (or any other languaje). Can be (1) for the other case
GROUP BY p.id
HAVING count(*) = howmuchattr;
see sqlfiddle here
see also this answer
Aside from any other issues, this query...
SELECT p.*
, pa.attribute_id
FROM products p
LEFT
-- OUTER (this keyword is optional in MySQL)
JOIN product_attributes pa
ON pa.product_id = p.id
WHERE pa.attribute_id IN('$attr_ids')
GROUP
BY p.id
HAVING COUNT(*) = $cnt;
... is logically identical to...
SELECT p.*
, pa.attribute_id
FROM products p
-- INNER (this keyword is also optional in MySQL)
JOIN product_attributes pa
ON pa.product_id = p.id
WHERE pa.attribute_id IN('$attr_ids')
GROUP
BY p.id
HAVING COUNT(pa.attribute_id) = $cnt;
In order to maintain the utility of the OUTER JOIN consider rewriting as follows...
SELECT p.*
, pa.attribute_id
FROM products p
LEFT
JOIN product_attributes pa
ON pa.product_id = p.id
AND pa.attribute_id IN('$attr_ids')
GROUP
BY p.id
HAVING COUNT(pa.attribute_id) = $cnt;
I have two tables in Mysql, Products and Inventory...
Products
int id_product
varchar name
Inventory
id_inventory
product_id
existence
So when my product '3' is out of stock I delete the row in Inventory where product_id = 3
And now I need to get all values that I have deleted on Inventory cause I need to make a report of missing products...
How can I make this query?
I used SELECT i.* FROM inventory i, products p WHERE i.product_id!=p.id_product but it doesn't works..
Thank you
LEFT JOIN would do as you wish as the rows you are looking for would have no corresponding row in inventory for a row in products, and so that gives the query ...
SELECT
p.product_id
FROM product p
LEFT JOIN inventory i
ON i.product_id = p.product_id
WHERE i.product_id IS NULL
Alternatively you could simply just not delete the row from inventory when unavailable. Just then do something like
SELECT
p.product_id
FROM product p
INNER JOIN inventory i
ON i.product_id = p.product_id
AND i.quantityInStock = 0
Either way works
or
select p.* from product p
where not exists (select null from inventory i where i.product_id=p.id_product)
I have 3 tables
products categories products_categories
------------ ------------- --------------------
product_id category_id product_id
product_title category_title category_id
Each product can belong to multiple categories as the db schema shows.
I join the three tables to get a listing of the three last inserted products.
SELECT p.product_id,
p.product_title,
c.category_id,
c.category_title
FROM products p
INNER JOIN products_categories pc ON p.product_id = pc.product_id
INNER JOIN categories c ON pc.category_id = c.category_id GROUP BY p.product_id LIMIT 3
With the above query I get the products but with the first category that the product belongs to.
My question is, is it possible by modifying the query to get all the categories that each product belongs to, in one row along with the product info?
Or the only way is to execute another query for each product while fetching the list to get its categories?
You could try:
SELECT p.product_id, p.product_title,
GROUP_CONCAT(c.category_title)
FROM products p
INNER JOIN products_categories pc ON p.product_id = pc.product_id
INNER JOIN categories c ON pc.category_id = c.category_id
GROUP BY p.product_id
See GROUP_CONCAT syntax here
Dont use "Group By". Then in your PHP Code group manually to product_id and collect all categories.