I've got the following Mysql structure:
jss_products
productID
price1
jss_extrafields_values
exvalID
productID
extraFieldID
jss_extrafields_prices
exvalID
price1
Each product has a few extrafields. I'm interested in extraFieldID = 1
I wish to update all of the price1 in jss_extrafields_prices using the value of jss_products.price1. I have the following query but it only updates the first entry per product in jss_extrafields_price, not all entries.
I'm trying to normalize the prices in jss_extrafields_prices so that for a product which has a price of 20.00, each relevant entry in jss_extrafields_prices becomes CURRENTPRICE - 20.
Does that make sense? Here's what I have so far
UPDATE jss_extrafields_prices AS JEP
INNER JOIN (
SELECT P.productID, P.price1 AS P1, EP.price1, EP.exvalID FROM jss_products AS P
INNER JOIN jss_extrafields_values AS EV
ON P.productID = EV.productID
INNER JOIN jss_extrafields_prices AS EP
ON EV.exvalID = EP.exvalID
WHERE EV.extraFieldID = 1
GROUP BY P.productID
ORDER BY P.productID DESC, EP.price1 DESC
) AS X
ON JEP.exvalID = X.exvalID
SET JEP.price1 = JEP.price1 - X.P1
I would expect the inner query to return something like:
productID = 1090
P1 = 20.8333333
price1 = 20.8333333
exvalID = 3236
Knowing that productID of 1090 has 3 pricing options and its base price is 20.83333 I would then want to update every matching product in jss_extrafields_prices to be the current price minus the base price.
Does that help?
Stripping away some of the information that was previously classes as being too localized, this simplified to an UPDATE with an INNER JOIN:
UPDATE jss_extrafields_prices
INNER JOIN (
SELECT P.productID, P.price1 AS baseprice, JEP.price1 AS optionprice, JEP.exvalID, (JEP.price1 - P.price1) AS adjustedprice FROM jss_products AS P
INNER JOIN jss_extrafields_values AS JEV
ON P.productID = JEV.productID
INNER JOIN jss_extrafields_prices AS JEP
ON JEV.exvalID = JEP.exvalID
WHERE JEV.extraFieldID = 1
) AS X
ON jss_extrafields_prices.exvalID = X.exvalID
SET jss_extrafields_prices.price1 = X.adjustedprice
Related
I building a custom SQL query for my module to retrieve all combinations of a product with id_product and multiple attributes ids, but currently, I only managed to select it with one attribute and no more, I'm really missing something but didn't find it yet.
To get in context here's my query to find all combinations (color & size) of a product and its result:
SELECT
p.id_product,
pq.quantity,
pa.price AS price_diff,
p.price,
pai.id_image,
pl.name,
GROUP_CONCAT(agl.id_attribute_group, ':', pal.id_attribute ORDER BY agl.id_attribute_group SEPARATOR ", ") as combination_ids,
GROUP_CONCAT(pal.name ORDER BY agl.id_attribute_group SEPARATOR ", ") as combination
FROM ps_product p
LEFT JOIN ps_product_attribute pa ON (p.id_product = pa.id_product)
LEFT JOIN ps_stock_available pq ON (p.id_product = pq.id_product AND pa.id_product_attribute = pq.id_product_attribute)
LEFT JOIN ps_product_lang pl ON (p.id_product = pl.id_product)
LEFT JOIN ps_product_attribute_combination pac ON (pa.id_product_attribute = pac.id_product_attribute)
LEFT JOIN ps_attribute_lang pal ON (pac.id_attribute = pal.id_attribute)
LEFT JOIN ps_attribute a ON (pal.id_attribute = a.id_attribute)
LEFT JOIN ps_attribute_group_lang agl ON (a.id_attribute_group = agl.id_attribute_group)
LEFT JOIN ps_product_attribute_image pai on(pa.id_product_attribute = pai.id_product_attribute)
WHERE pl.id_lang = 1
AND pal.id_lang = 1
AND agl.id_lang = 1
AND p.id_product = 3196 -- My product
GROUP BY pac.id_product_attribute
The result
Query with a single attribute (size S for this example):
......................
......................
AND p.id_product = 3196 -- My product
AND agl.id_attribute_group = 9 -- size
AND pal.id_attribute = 761 -- 'S' size for my case
GROUP BY pac.id_product_attribute
But no success with specifying both size AND color, any idea?
I think you want a HAVING clause. To filter on two attributes, the logic would be:
SELECT ...
FROM ...
WHERE ...
GROUP BY pac.id_product_attribute
HAVING
MAX(agl.id_attribute_group = 9 AND pal.id_attribute = 761) = 1
AND MAX(agl.id_attribute_group = 2 AND pal.id_attribute = 727) = 1
I should warn that your code is not a valid aggregation query. You need more column in the GROUP BY clause to fix that flaw. It is hard to tell for sure without seeing your data, but, with a few assumptions on the primary key of each table:
GROUP BY
p.id_product,
pa.id_product_attribute,
pac.id_product_attribute,
pai.id_image,
pq.id -- if that exists?
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
I know this is simple but I'm have a mental block.
I need to update all products that belongs to a category. The product is assigned to a category in an association table.
so it's something like
UPDATE product P1
SET myflag = 1
WHERE P1.productid IN (
SELECT CA.productid
FROM category_associations CA
WHERE CA.categoryid = '500'
)
is there a better way?
A JOIN will typically have the optimal execution plan, but IN can be inefficient:
UPDATE
product P1 JOIN
category_associations ca
ON ca.productId = P1.productId
AND ca.categoryId = '500'
SET P1.myflag = 1
another way to write it is:
UPDATE product
SET myflag = 1
FROM product P1 JOIN
category_associations ca
ON ca.productId = P1.productId
WHERE ca.categoryId = '500'
Basically I have product and several models for those products. Each model has a price.
This is what I intended to do:
Mark a product as featured, then have it's title, description, number 1 image's thumbnail and the price for the cheapest model
This is my current query:
SELECT
product.title,
product.url_name,
product.description,
price.price,
image.thumbnail
FROM
mps_contents AS product
LEFT OUTER JOIN
mps_contents AS image
ON
image.page_id = product.content_id AND
image.display_order = '1' AND
image.resource_type = 'image'
LEFT OUTER JOIN
mps_contents AS model
ON
product.content_id = model.page_id
INNER JOIN
mps_product_info AS price
ON
model.content_id = price.content_id
WHERE
product.active = '1' AND
product.resource_type = 'product' AND
product.featured = '1'
ORDER BY RAND( )
LIMIT 3
You may see that my query cannot do the price sorting, I hope somebody could help me with that. An additional problem that I encounter is if I have multiple models for a product. I end up getting a set that has prices for 2 models from a single product when the intent is to have the 1 price for each product.
I am aware of the issue with ORDER BY RAND() but I will ignore it since I don't think this site will have more that 50 products.
I think something like this should work....
SELECT
product.title,
product.url_name,
product.description,
A.price,
image.thumbnail
FROM
mps_contents AS product
LEFT OUTER JOIN
mps_contents AS image
ON
image.page_id = product.content_id AND
image.display_order = '1' AND
image.resource_type = 'image'
LEFT OUTER JOIN (
SELECT price.price
FROM mps_contents AS model
JOIN mps_product_info price ON (model.content_id = price.content_id)
WHERE model.page_id = product.content_id
ORDER BY price.price
LIMIT 1
) AS A
WHERE
product.active = '1' AND
product.resource_type = 'product' AND
product.featured = '1'
ORDER BY RAND( )
LIMIT 3
I have a correlated subquery that will return a list of quantities, but I need the highest quantity, and only the highest. So I tried to introduce an order by and a LIMIT of 1 to achieve this, but MySQL throws an error stating it doesn't yet support limits in subqueries. Any thoughts on how to work around this?
SELECT Product.Name, ProductOption.Name, a.Qty, a.Price, SheetSize.UpgradeCost,
FinishType.Name, FinishOption.Name, FinishTierPrice.Qty, FinishTierPrice.Price
FROM `Product`
JOIN `ProductOption`
ON Product.idProduct = ProductOption.Product_idProduct
JOIN `ProductOptionTier` AS a
ON a.ProductOption_idProductOption = ProductOption.idProductOption
JOIN `PaperSize`
ON PaperSize.idPaperSize = ProductOption.PaperSize_idPaperSize
JOIN `SheetSize`
ON SheetSize.PaperSize_idPaperSize = PaperSize.idPaperSize
JOIN `FinishOption`
ON FinishOption.Product_idProduct = Product.idProduct
JOIN `FinishType`
ON FinishType.idFinishType = FinishOption.Finishtype_idFinishType
JOIN `FinishTierPrice`
ON FinishTierPrice.FinishOption_idFinishOption = FinishOption.idFinishOption
WHERE Product.idProduct = 1
AND FinishTierPrice.idFinishTierPrice IN (SELECT FinishTierPrice.idFinishTierPrice
FROM `FinishTierPrice`
WHERE FinishTierPrice.Qty <= a.Qty
ORDER BY a.Qty DESC
LIMIT 1)
This is a variation of the greatest-n-per-group problem that comes up frequently.
You want the single row form FinishTierPrice (call it p1), matching the FinishOption and with the greatest Qty, but still less than or equal to the Qty of the ProductOptionTier.
One way to do this is to try to match a second row (p2) from FinishTierPrice that would have the same FinishOption and a greater Qty. If no such row exists (use an outer join and test that it's NULL), then the row found by p1 is the greatest.
SELECT Product.Name, ProductOption.Name, a.Qty, a.Price, SheetSize.UpgradeCost,
FinishType.Name, FinishOption.Name, FinishTierPrice.Qty, FinishTierPrice.Price
FROM `Product`
JOIN `ProductOption`
ON Product.idProduct = ProductOption.Product_idProduct
JOIN `ProductOptionTier` AS a
ON a.ProductOption_idProductOption = ProductOption.idProductOption
JOIN `PaperSize`
ON PaperSize.idPaperSize = ProductOption.PaperSize_idPaperSize
JOIN `SheetSize`
ON SheetSize.PaperSize_idPaperSize = PaperSize.idPaperSize
JOIN `FinishOption`
ON FinishOption.Product_idProduct = Product.idProduct
JOIN `FinishType`
ON FinishType.idFinishType = FinishOption.Finishtype_idFinishType
JOIN `FinishTierPrice` AS p1
ON p1.FinishOption_idFinishOption = FinishOption.idFinishOption
AND p1.Qty <= a.Qty
LEFT OUTER JOIN `FinishTierPrice` AS p2
ON p2.FinishOption_idFinishOption = FinishOption.idFinishOption
AND p2.Qty <= a.Qty AND (p2.Qty > p1.Qty OR p2.Qty = p1.Qty
AND p2.idFinishTierPrice > p1.idFinishTierPrice)
WHERE Product.idProduct = 1
AND p2.idFinishTierPrice IS NULL