MySQL update from nested SELECT query - mysql

I have 2 tables which are getting different values from different sources.
One table called stock has 2 fields, code and stock, while other have code, stock (and bunch more not relevant to what I want to do)
Basically my current query for checking if there are enough quantities is following
SELECT *
FROM products
WHERE products.code
NOT IN (SELECT stock.code from stock)
AND products.stock > 0
AND products.product_active = 1
Which works, but I would like to extend it to UPDATE stock field of the table products to value 0 for the results of the above query.
Thanks

Try this:
UPDATE products p
LEFT JOIN stock s ON p.code = s.code
SET p.stock = 0
WHERE p.stock > 0 AND p.product_active = 1 AND s.code IS NULL

So why don't you do it? Its very similar to what you just did :
UPDATE products p
SET p.stock = 0
WHERE p.code NOT IN(SELECT s.code FROM stock s)
AND p.stock > 0
AND p.product_Active = 1
I don't like to use IN() statement, since it doesn't handle NULL values very well, you can also use NOT EXISTS() instead of it:
UPDATE products p
SET p.stock = 0
WHERE NOT EXISTS(SELECT 1 FROM stock s
WHERE p.code = s.code)
AND p.stock > 0
AND p.product_Active = 1

Related

How to update quantity referencing another table php/mysql

I'm a bit of a noob and I'm sure this is fairly simple but I've tried different things and I can't get my head around it.
I have a product table that contains a category id and I want to set the quantity to 0 which is stored in another table.
This is the last thing I tried:
function wipeprod(){
UPDATE stock_available
INNER JOIN
product stock_available
ON
(
product.id_category_default != 3
OR
product.id_category_default != 10
OR
product.id_category_default != 943
)
SET
stock_available.quantity = 0;
}
Thanks in advance.
I suspect that you want to set column quantity in table stock_available to 0 for products that are not in categories 3, 10, and 943.
If so, you can use the update ... join syntax as follows:
update stock_available s
inner join product p on p.product_id = s.product_id
set s.quantity = 0
where p.id_category_default not in (3, 10, 943)
The main problems with your original query are:
the join is missing a predicate on product_id
you wanted AND condition rather than OR; NOT IN comes handy to shorten this.
You can use such an update statement by use of INNER JOIN :
UPDATE stock_available s
JOIN
(
SELECT id
FROM product
WHERE id_category_default NOT IN (3,10,943)
) AS p ON p.id = s.product_id
SET
s.quantity = 0;
where no need a proper query after the keyword JOIN

MySQL - Update a series of grouped rows if one of them contains a value (set all products to live if even only one is in stock)

I'm looking for the concise answer to this issue. I'm trying to update a load of rows in a product table. Currently only in-stock items are set to active. I'm looking to create a quick statement that'll set any others with the same "linked_id" to active and not deleted. So far i've got here:
UPDATE products
SET active=1, deleted=0
WHERE stock>=1
OR warehouse_stock>=1
GROUP BY linked_id
Obviously, this isnt going to work as you cant GROUP BY in an update statement!?
You can do it with a self join:
UPDATE products p INNER JOIN products pp
ON pp.linked_id = p.linked_id
SET p.active = 1, p.deleted = 0
WHERE (p.active = 0 OR p.deleted = 1) AND (pp.stock >= 1 OR pp.warehouse_stock >= 1)
I guess the condition for the rows to be updated is:
p.active = 0 OR p.deleted = 1

SQL Query based on multiple where conditions

I've got a script where checked in employee's can see the stock inventory from each other, linked with their personal stock location, so each checked in employee can see which items are in stock at different locations. However, I want the main stock (id of 1, which is not attached to an employee) to be showed always, but I can't get the query right because one of the where statements is clearly not correct:
`stock_locations`.`location_id` = 1 AND
`workschedule`.`checkedIn` = 1 AND
Rememeber, the main stock is not linked to an employee, so it doesn't show up at the workschedule table. If I remove the first statement, It clearly shows up all the checked in employee's with their location, but that doesn't give me the main stock. If I remove the second statement, it only shows me the main stock.
How can I solve this issue within SQL? This is btw the full statement:
SELECT
`item_quantities`.`item_id`,
`stock_locations`.`location_name`,
`item_quantities`.`quantity`,
`people`.`first_name`
FROM
`item_quantities`
JOIN `stock_locations` ON `item_quantities`.`location_id` = `stock_locations`.`location_id`
JOIN `items` ON `item_quantities`.`item_id` = `items`.`item_id`
LEFT JOIN `workschedule` ON `workschedule`.`linked_storage` = `stock_locations`.`location_id`
LEFT JOIN `people` ON `workschedule`.`employee_id` = `people`.`person_id`
WHERE
`stock_locations`.`location_id` = 1 AND
`workschedule`.`checkedIn` = 0 AND
`items`.`unit_price` != 0 AND
`items`.`deleted` = 0 AND
`stock_locations`.`deleted` = 0 NULL
Thanks in advance!
Make it an OR statement inside of parens.
(`stock_locations`.`location_id` = 1 OR `workschedule`.`checkedIn` = 1) AND
This will return all records that match either the main stock or the employee.
You need to use the OR operator. Clearly both things can't happen at the same time, so you need to specify each set of acceptable conditions.
SELECT
`item_quantities`.`item_id`,
`stock_locations`.`location_name`,
`item_quantities`.`quantity`,
`people`.`first_name`
FROM
`item_quantities`
JOIN `stock_locations`
ON `item_quantities`.`location_id` = `stock_locations`.`location_id`
JOIN `items`
ON `item_quantities`.`item_id` = `items`.`item_id`
LEFT JOIN `workschedule`
ON `workschedule`.`linked_storage` = `stock_locations`.`location_id`
LEFT JOIN `people`
ON `workschedule`.`employee_id` = `people`.`person_id`
WHERE
`stock_locations`.`location_id` = 1
OR (
AND `workschedule`.`checkedIn` = 1
AND `items`.`unit_price` != 0
AND `items`.`deleted` = 0
AND `stock_locations`.`deleted` = 0
NULL
)
You have LEFT JOIN, but your WHERE clause turns them into inner joins. Fixing that will probably fix your problem:
SELECT . . .
FROM item_quantities iq JOIN
stock_locations sl
ON iq.`location_id` = sl.`location_id` JOIN
items i
ON iq.`item_id` = i.`item_id` LEFT JOIN
workschedule ws
ON ws.`linked_storage` = sl.`location_id` AND
ws.`checkedIn` = 0 LEFT JOIN
--------^
people p
ON ws.`employee_id` = p.`person_id`
WHERE sl.`location_id` = 1 AND
i.`unit_price` != 0 AND
i.`deleted` = 0 AND
sl.`deleted` = 0

Mysql LEFT JOIN in combination with optional relation parent<->child table not working

I am having some troubles when combining left joins with optional values to group by.
In short we have
table child products: catalog
table parent relations - if it exists! contains parent child relations : catalog_product_relation
table warehouses : warehouses
table products and stock : wh_products
and we are trying to get the stock total qty, where
stock is stored by child products and needs to be summed per that
if a parent relation exists then we should group by and show that data
even simpler
for products without a parent: just sum qty (already works)
for products with a parent: then rollup and sum by the parent identifier
and preferably also get the data for the parent identifier from the catalog (ie the right name and sku)
I hope it is clear ... the query below is not working. Step 1 to me looked like just getting the parent ID in a column
and step 2 is to sum the qty's for simple products per simple product and for parent products sum it up for all child simple product but show the parent data
select c.sku as sku,
IFNULL(pr.parent_id, c.entity_id) as main_id,
c.type_id as type,
SUM(CASE WHEN (wh.code='LR') THEN FLOOR(wp.qty) ELSE 0 END) AS 'Loc1',
SUM(CASE WHEN (wh.code='LS') THEN FLOOR(wp.qty) ELSE 0 END) AS 'Loc2'
FROM catalog c,
wh_products wp,
warehouses wh
LEFT JOIN catalog_product_relation pr ON pr.parent_id = c.entity_id
WHERE c.entity_id = wp.product_id and wp.warehouse_id = wh.warehouse_id and wp.qty > 0
GROUP BY main_id
I would start by writing the JOINs correctly and aggregating by the columns in the SELECT:
SELECT c.sku as sku,
COALESCE(pr.parent_id, c.entity_id) as main_id, c.type_id as type,
SUM(CASE WHEN wh.code = 'LR' THEN FLOOR(wp.qty) ELSE 0 END) AS Loc1,
SUM(CASE WHEN wh.code = 'LS' THEN FLOOR(wp.qty) ELSE 0 END) AS Loc2
FROM catalog c LEFT JOIN
wh_products wp
ON c.entity_id = wp.product_id LEFT JOIN
warehouses wh
ON wp.warehouse_id = wh.warehouse_id AND wp.qty > 0 LEFT JOIN
catalog_product_relation pr
ON pr.parent_id = c.entity_id
GROUP BY c.sku, COALESCE(pr.parent_id, c.entity_id), c.type_id;
I'm not sure if this fixes your problems. Without sample data and desired results, it is a bit hard to follow the logic.

MySQL LEFT JOIN where multiple values

I have query that joins Products table on Product_Attributes table. I' would like to get products which meat exact condition ex.
Products which have attribute id 9 AND 16 selected, but when I run this query I'll get only product which meets first ID
WHERE ("AttributeValueID" = 9 AND "AttributeValueID" = 16)
I need that products to have both attributes selected AttributeValueID = 9 AND AttributeValueID = 9 not only this or that attribute ID. Using OR / IN is'not solution for me.
Update:
below is a part of query with join / where:
LEFT JOIN "Product_Attributes" ON "Product_Attributes"."ProductID" = "SiteTree_Live"."ID" WHERE ("PriceTax" >= '100' AND "PriceTax" <= '200') AND ("AttributeValueID" IN ('9','8','7')) AND ("AttributeValueID" IN ('5','4'))
thank you in advance for your help
This is an example of a "set-within-sets" query. I like to solve these using group by and having, because that is a very flexible approach:
select pa.ProductId
from ProductAttributes pa
group by pa.ProductId
having sum(AttributeValueId = 9) > 0 and
sum(AttributeValueId = 16) > 0;
Gordon's answer showed the most flexible way to get the list of ProductId values that meet the specified criteria.
You could use a query like Gordon's (that gets the set of ProductId) as an inline view, and do a JOIN operation against the products table, like this:
SELECT p.ProductID
, p.ProductName
, ...
FROM products p
JOIN (
SELECT a.ProductID
FROM ProductAttributes a
GROUP BY a.ProductId
HAVING SUM(a.AttributeValueID=9) > 0
AND SUM(a.AttributeValueID=16) > 0
) s
ON s.ProductID = p.ProductID
UPDATE
based on the edit to the question adding a snippet of SQL text:
JOIN ( SELECT a.ProductID
FROM Product_Attributes a
HAVING SUM(a.AttributeValueID IN ('9','8','7')) > 0
AND SUM(a.AttributeValueID IN ('5','4')) > 0
GROUP BY a.ProductID
) s
ON s.ProductID = SiteTree_Live.ID
WHERE SiteTree_Live.PriceTax >= '100'
AND SiteTree_Live.PriceTax <= '200'