I'm pretty new to SQL/PHP and I'm trying to LEFT JOIN two tables with the second table LEFT JOINed twice.
Here the scenario:
I have two tables, products and productvariations. In the productvariations table I also have a column 'colorvalue' that tells the user whether it's the standard color or a special color for the products.
products
idproducts | product | checked
-------------------------------
1 | testpr1 | 0
2 | testpr2 | 0
...
productvariations
productid | colorvalue | price
-------------------------------
1 | 0 | 12.50
1 | 1 | 10.25
2 | 0 | 14.50
2 | 1 | 13.00
...
Now what I want to do is to SELECT all columns of products and LEFT JOIN to them the twice the productvariations table to have two different additional columns for the price. But only those products that have the checked value = '0'.
From different other Q&A I set up this code, but somehow it doesn't give me any results. Can someone help?
SELECT products.*, productvar1.price_single, productvar1.price_palette, productvar2.price_single, productvar2.price_palette, productvar1.price_specialconditions, productvar1.price_colorchange
FROM products
LEFT JOIN productvariations AS productvar1
ON products.idproducts = productvar1.product AND productvar1.colorvlaue = '0'
LEFT JOIN productvariations AS productvar2
ON products.idproducts = productvar2.product AND productvar2.colorvalue = '1'
WHERE products.checked = '0' LIMIT 200;
Your query had some typos and of course there was a column in the select clause that I did not see in the table, but now the following query works according to the information in the table.
SELECT products.*,
productvar1.colorvalue as colorvalue1,
productvar1.price as price1,
productvar2.colorvalue as colorvalue2,
productvar2.price as price2
FROM PT1 products
LEFT JOIN productvariations AS productvar1
ON products.idproducts = productvar1.productid AND productvar1.colorvalue = '0'
LEFT JOIN productvariations AS productvar2
ON products.idproducts = productvar2.productid AND productvar2.colorvalue = '1'
WHERE products.checked = '0' LIMIT 200;
demo in db<>fiddle
Related
I'm pretty new to SQL and this might be a really dumb and easy question, but I couldn't solve it myself, so here's the scenario:
I have two tables, products and productvariations kinda like this.
products
idproducts | product | ... | checked
-------------------------------------
1 | testpr1 | ... | 0
2 | testpr2 | ... | 0
3 | testpr3 | ... | 1
...
productvariations
productid | colorvalue | price_single | price_palette | ...
------------------------------------------------------------
1 | 0 | 12.50 | 11.50 | ...
1 | 1 | 10.25 | 10.00 | ...
2 | 0 | 14.50 | 13.75 | ...
2 | 1 | 13.00 | 11.50 | ...
2 | 1 | 12.50 | 12.00 | ...
...
With 2x LEFT JOIN I try to get the respective price_single and price_palette as well as some other columns from the productvariations table depending on the colorvalue. The first LEFT JOIN with colorvalue = '0' works perfect, since there's only one row per product with colorvalue = '0'. But the second LEFT JOIN returns a new resultrow for every row that has colorvalue = '1' of the respective product, since there can be several rows with that colorvalue. This is the code I have so far:
SELECT products.*, productvar1.price_single, productvar1.price_palette, productvar2.price_single, productvar2.price_palette, productvar1.price_specialconditions, productvar1.price_colorchange,
FROM products
LEFT JOIN productvariations AS productvar1
ON products.idproducts = productvar1.product AND productvar1.colorvalue = '0'
LEFT JOIN productvariations AS productvar2
ON products.idproducts = productvar2.product AND productvar2.colorvalue = '1'
WHERE products.checked = '0' LIMIT 200;
From questions like this (LEFT JOIN only first row) I understand that I somehow have to use MIN() in a subquery. But since I'm pretty new to SQL I don't really understand how to exactly apply this. This is what I tried and I know it doesn't make sense at all, but this was one of my desperate tries yesterday to understand and make it work:
SELECT products.*, productvar1.price_single, productvar1.price_palette, productvar2.price_single, productvar2.price_palette, productvar1.price_specialconditions, productvar1.price_colorchange,
FROM products
LEFT JOIN productvariations AS productvar1
ON products.idproducts = productvar1.product AND productvar1.colorvalue = '0'
LEFT JOIN
(SELECT product, MIN(price_single), MIN(price_palette)
FROM productvariations AS productvar2
WHERE productvar2.products = producst.idproducts AND productvar2.colorvalue = '1'
GROUP BY product) AS productvar2
ON products.idproducts = productvar2.product AND productvar2.colorvalue = '1'
WHERE products.checked = '0' LIMIT 200;
WORKING SOLUTION by shubham
SELECT products.*, productvar1.price_single, productvar1.price_palette, productvar2.price_single, productvar2.price_palette
FROM products
LEFT JOIN productvariations AS productvar1
ON products.idproducts = productvar1.productid AND productvar1.colorvalue = '0'
LEFT JOIN
(SELECT productvar.productid, MIN(productvar.price_single)as price_single , MIN(productvar.price_palette) as price_palette,productvar.colorvalue
FROM productvariations AS productvar inner join products on productvar.productid = products.idproducts
WHERE productvar.productid = products.idproducts AND productvar.colorvalue = '1'
GROUP BY productvar.productid) AS productvar2
ON products.idproducts = productvar2.productid AND productvar2.colorvalue = '1'
WHERE products.checked = '0' LIMIT 200;
SELECT products.*, productvar1.price_single, productvar1.price_palette, productvar2.price_single, productvar2.price_palette
FROM products
LEFT JOIN productvariations AS productvar1
ON products.idproducts = productvar1.productid AND productvar1.colorvalue = '0'
LEFT JOIN
(SELECT productvar.productid, MIN(productvar.price_single)as price_single , MIN(productvar.price_palette) as price_palette,productvar.colorvalue
FROM productvariations AS productvar inner join products on productvar.productid = products.idproducts
WHERE productvar.productid = products.idproducts AND productvar.colorvalue = '1'
GROUP BY productvar.productid) AS productvar2
ON products.idproducts = productvar2.productid AND productvar2.colorvalue = '1'
WHERE products.checked = '0' LIMIT 200;
Here is SQL Fiddle link, I am not sure what you want but I think this maybe help.
I've the follow SQL schema:
+----------+
| products |
+----------+
| id |
| name |
+----------+
^ 8
|
v 1
+-------------+
| values |
+-------------+
| value |
| product_id |
| property_id |
+-------------+
^ 8
|
v 1
+------------+
| properties |
+------------+
| id |
| name |
+------------+
One product has many properties and a property belongs to many products. The values table is the join table for the many_to_many association between products and properties. And in this table is saved the value of the property for a product.
Now I'm looking for a query to select all products with property x with value a, and property y with value b ecc. My try is this query but return no records:
SELECT DISTINCT
products.*
FROM
products
INNER JOIN
product_values
ON product_values.product_id = products.id
INNER JOIN
properties
ON properties.id = product_values.property_id
WHERE
(properties.name = 'size' AND product_values.value = 'big')
AND (properties.name = 'color' AND product_values.value = 'red')
If possible I need a query with no nested select.
Since a property can not be color and size at the same time you need to use OR in your where clause. Then group the data and check if both are in the group with having
SELECT products.id, products.name
FROM `products`
INNER JOIN `product_values` ON `product_values`.`product_id` = `products`.`id`
INNER JOIN `properties` ON `properties`.`id` = `product_values`.`property_id`
WHERE (properties.name = 'size' AND product_values.value = 'big')
OR (properties.name = 'color' AND product_values.value = 'red')
GROUP BY products.id, products.name
HAVING count(distinct properties.name) = 2
I would do this using group by and having:
select pv.product_id
from product_values pv join
properties p
on pv.property_id = p.id
where (p.name, v.value) in ( ('size', 'big'), ('color', 'red') )
group by pv.product_id
having count(distinct p.name) = 2;
Another approach using sum to filter multiple attributes for an entity
SELECT
`p`.*
FROM
`products` p
INNER JOIN `product_values` v
ON `v`.`product_id` = `p`.`id`
INNER JOIN `properties` pr
ON `pr`.`id` = `v`.`property_id`
GROUP BY p.id
HAVING SUM (pr.name = 'size' AND v.value = 'big')
AND SUM(pr.name = 'color' AND v.value = 'red')
SELECT li_1.carrier, li_1.product_id, li_1.quantity, products_description.products_name, sites.sites_id, sites.sites_name, counted_table.counted
FROM inventory li_1
INNER JOIN products_description ON li_1.product_id = products_description.products_id
INNER JOIN sites ON products_description.data = sites.data
INNER JOIN (
SELECT SUM( li_2.quantity ) AS counted
FROM inventory li_2
WHERE li_1.product_id = li_2.product_id
) counted_table
GROUP BY li_1.product_id
ORDER BY li_1.id DESC
I'm attempting to use the parent id (product_id) to count the total amount of quantity for each product in the subquery - But I only get the standard mysql error message.
So something like
id | quantity | total
---------------------------------
0001 | 2 | 6
| |
0001 | 4 | 6
What could be wrong?
if you change sub-query, it could be fixed
SELECT li_1.carrier, li_1.product_id, li_1.quantity, products_description.products_name, sites.sites_id, sites.sites_name, counted_table.counted
FROM inventory li_1
INNER JOIN products_description ON li_1.product_id = products_description.products_id
INNER JOIN sites ON products_description.data = sites.data
INNER JOIN (
SELECT product_id,SUM( li_2.quantity ) AS counted
FROM inventory li_2
GROUP BY li_2.product_id
) counted_table ON li_1.product_id = counted_table.product_id
ORDER BY li_1.id DESC
This is my situation.
I have 3 tables
Orders
- id status deleted
Order Lines
- related_id related_model quantity
Products
- id code price price_purchase
I want to create a list with all products. The amount of times they are purchased and a sum of the gross margin (price - price_purchase). It must only use orders lines with the related model set to 'products'. And secondly it must only pick orders with the status set to 'paid, processing, sent, ready_for_pickup or picked_up' and with the order not deleted.
So this would be the result I want:
id | code | purchases | value
-------------------------------
1 | code1 | 7 | 57,05
2 | code2 | 122 | 254,98
3 | code3 | 0 | 0,00
This is the SQL query I have so far:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
LEFT JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
LEFT JOIN shop_orders so ON so.id = sol.order_id
WHERE so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
GROUP BY p.id
It returns the correct data. But not all problems. That is my problem. I a lot of different methods like sub queries and other methods but can't seem to solve the problem. I know the problem is my LEFT join, but don't know a solution to my problem.
I'm using MySQL Workbench.
Any help is welcome.
Your joins are wrong. You need to identify the order lines to consider separately from and prior to forming the LEFT JOIN with the product details. An inline view could help:
SELECT
p.id,
p.code,
IFNULL(SUM(ordered_item.quantity) , 0) as purchases ,
sum((p.price - p.price_purchase) * ordered_item.quantity) as value
FROM
products p
LEFT JOIN (
SELECT
sol.related_id AS related_id,
sol.quantity AS quantity
FROM
shop_orders_lines sol
INNER JOIN shop_orders so
ON so.id = sol.order_id
WHERE
so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
AND sol.related_model = 'products'
) ordered_item
ON ordered_item.related_id = p.id
GROUP BY p.id
Move outer table conditions from WHERE to ON, otherwise the OUTER JOIN works like a regular INNER JOIN:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
LEFT JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
LEFT JOIN shop_orders so ON so.id = sol.order_id AND
so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0
GROUP BY p.id
Is p.id the whole primary key for that table? If not, you need to find out how to treat p.code. (Either list in GROUP BY, or use as argument to aggregate function.)
Another try:
SELECT p.id, p.code, IFNULL(SUM(sol.quantity) , 0) as purcahses,
sum((p.price - p.price_purchase) * quantity) as value
FROM products p
JOIN shop_orders_lines sol ON sol.related_id = p.id
AND sol.related_model = 'products'
WHERE EXISTS (select 1 from shop_orders so
where so.id = sol.order_id
AND so.status IN ('paid', 'processing', 'sent', 'ready_for_pickup', 'picked_up')
AND so.deleted = 0)
GROUP BY p.id
Table products:
id|name
-------
1 |computer
2 |microwave
3 |transl
Table product_features:
feature | id_product | feature_value
------------------------------------
count_of_buttons | 1 | 1
count_of_buttons | 2 | 2
count_of_buttons | 3 | 1
color | 1 | white
color | 2 | white
color | 3 | black
Pls, how to get all white products with one button?
Thank you very much!
select product.*
from product
join product_features as buttons
on buttons.id_product = product.id
join product_features as color
on color.id_product = product.id
where buttons.feature_value = '1'
and buttons.feature = 'count_of_buttons'
and color.feature_value = 'white'
and color.feature = 'color';
select
p.id
p.name
from
products p
join (select * from product_features where feature = 'color') colors on (p.id=colors.id_product)
join (select * from product_features where feature = 'count_of_buttons') buttons on (p.id=buttons.id_product)
where
colors.feature_value = 'white'
and buttons.feature_value = 1
You might consider reorganizing the product_features table so that you have a separate column for each feature (i.e. a color column and a count_of_buttons column) so that you have one row for each product. In fact it could all be in the products table.
SELECT
p.id
FROM products p
JOIN product_features pf
ON p.id = pf.id
WHERE pf.feature_value = 'white' AND pf.count_of_buttons = 1
select p.id, p.name from products p inner join product_features ON p.id=id_product where feature_value='white' and feature='color' and count_of_buttons=1