Using var into an insert update request does not work - mysql

I try to insert values into a table using following request :
INSERT IGNORE itemmaster
(
SKU,
product_id
)
SELECT
#massimport_SKU := main.SKU,
#massimport_product_id := prd.entity_id
FROM itemmaster AS main
INNER JOIN product_entity AS prd ON prd.sku = main.SKU
ON DUPLICATE KEY UPDATE product_id = #massimport_product_id
SKU is a unique key.
The problem is the value of product_id is always the same id. If I only execute the select, product_id are different but after insert, only one value in product_id column. I think this is a problem with var #massimport_product_id cause if I useON DUPLICATE KEY UPDATE product_id = prd.entity_id instead the request work perfectly.
But cause it's an automatic generated request who work well in all other case, I hope somebody coul me explain why this append.
Thx

Don't use session variables, that can't work.
Use this:
INSERT IGNORE itemmaster( SKU, product_id )
SELECT main.SKU, prd.entity_id
FROM itemmaster AS main
INNER JOIN product_entity AS prd ON prd.sku = main.SKU
ON DUPLICATE KEY UPDATE product_id = prd.entity_id
;
Demo --> http://www.sqlfiddle.com/#!2/592187/1
However INNER JOIN in this query always returns records (values of SKU column), that already exist in itemmaster table, so INSERT is useles in this case, and the same can be done simpler, using multitable update:
UPDATE itemmaster main
JOIN product_entity AS prd ON prd.sku = main.SKU
SET main.product_id = prd.entity_id;
Demo: http://www.sqlfiddle.com/#!2/762eb4/1

Related

mySQL UPDATE WHERE with subquery gives error

I want to update a table with a subquery and always get an error.
Now i made a very simplified version (which makes not much sense but shows my error)
UPDATE a_test SET categoryID = '2956' WHERE id IN (
(
SELECT id from a_test
)
)
This ends in this error:
#1093 - Table 's_articles_categories' is specified twice, both as a target for 'UPDATE' and as a separate source for data
Why do i get this error?
When i use aliasses for the table a_test i get the same error.
This is the full query i want to use with the same error:
UPDATE s_articles_categories SET categoryID = '2956' WHERE id IN
(
SELECT s_articles_categories.id FROM `s_articles`
LEFT JOIN s_articles_categories ON s_articles.id = s_articles_categories.articleID
WHERE s_articles_categories.categoryID NOT IN (
SELECT id FROM s_categories
WHERE s_categories.id NOT IN (SELECT parent FROM s_categories WHERE parent IS NOT null GROUP BY parent)
)
)
One solution to the simplified query is to wrap the subquery inside another subquery:
UPDATE a_test
SET categoryID = '2956'
WHERE id IN (SELECT id FROM (SELECT id FROM a_test) x );
This trick forces MySQL to materialize the subquery on a_test, so that the values coming from the subquery aliased as x are not affected as the update proceeds.

UPDATE COALESCE query with null values

Definitely a basic question, but I couldn't find an example.
I'm writing a procedure which merges two rows into the good row. It moves all child rows' ids to being the correct one, replaces all NULL values with available values in the row being removed before finally deleting the 'bad' row.
What I have so far is this:
CREATE DEFINER=`danielv`#`%`
PROCEDURE `emp_merge`(IN `#core_emp_id` int, IN `#bad_emp_id` int)
BEGIN
UPDATE claim SET employee_id = #core_emp_id
WHERE employee_id = #bad_emp_id;
WITH bad_employee_values AS (
SELECT * FROM employee WHERE employee_id = #bad_emp_id
)
UPDATE employee SET
employee.employment_date = COALESCE(employee.employment_date, bad_employee_values.employment_date),
WHERE employee_id = #core_emp_id;
DELETE FROM employee WHERE employee_id = #bad_emp_id;
END
However, I'm getting non-descript error messages and I'm not sure why. I suspect there's an issue with how I'm handling my CTE and coalesce function, but I'm not sure where the gap in my understanding is.
In this statement :
WITH bad_employee_values AS (SELECT * FROM employee WHERE employee_id = #bad_emp_id)
UPDATE employee SET
employee.employment_date = COALESCE(employee.employment_date, bad_employee_values.employment_date),
WHERE employee_id = #core_emp_id;
You are defining CTE bad_employee_values but you are not using it in the UPDATE part of the query, hence you cannot access its columns : for MySQL, bad_employee_values.employment_date is unknown.
It looks like you could simply avoid a CTE here. You could just self-join the table, like so :
UPDATE employee e_core
INNER JOIN employee e_bad ON e_bad.employee_id = #bad_emp_id
SET e_core.employment_date = e_bad.employment_date,
WHERE employee_id = #core_emp_id AND e_core.employment_date IS NULL
This query will simply select the record identified by #core_emp_id, join it with the corresponding "bad" record, and copy the value of employment_date. The second condition in the WHERE clause prevents records whose employment_date is not null from being selected.

fixing duplicate fields in mysql table with update statement

I have inherited a table with a field "sku" with should be unique, but thanks to a failing sku-generating method is now littered with dozens of duplicates all around.
I need to quickly fix these duplicates (other parts of the application are failing when encountering these duplicate records) by running an update and appending the record ID to the SKU (which is a valid solution for the time being for this application).
I'm trying to run:
UPDATE
main_product_table
SET sku = CONCAT(sku, '-', CAST(product_id as CHAR) )
WHERE sku IN (
SELECT sku FROM main_product_table
GROUP BY sku
HAVING COUNT(*) > 1
);
But I receive:
You can't specify target table 'main_product_table' for update in FROM clause
Is there a way to accomplish the same? Is mysql complaining about me having main_product_table both in the update and in the subquery to get the duplicates?
Thanks!
Try this:
UPDATE
main_product_table
SET sku = CONCAT(sku, '-', CAST(product_id as CHAR) )
WHERE sku IN (
select * from ( SELECT sku FROM main_product_table
GROUP BY sku
HAVING COUNT(*) > 1) as p
);
Added table alias in inner query.

update all rows where there is a fk constraint issue

I'm migrating a table into a new database. There is a fk constraint problem because there was never a relationship set between the 2 tables (tbl_contacts.contact_ID and tbl_communications.contact_ID which is the fk). I can see all the rows with
SELECT * FROM Farm.tbl_communication as S
LEFT JOIN Farm.tbl_contacts ON S.contact_ID = Farm.tbl_contacts.contact_ID
WHERE Farm.tbl_contacts.contact_ID IS NULL
I was just trying to delete those rows and I tried this:
DELETE FROM Farm.tbl_communication
WHERE Farm.tbl_communication.contact_ID (SELECT contact_ID
FROM ( SELECT * FROM Farm.tbl_communication) as S
LEFT JOIN Farm.tbl_contacts ON S.contact_ID = Farm.tbl_contacts.contact_ID
WHERE Farm.tbl_contacts.contact_ID IS NULL)
Which did not work. I have now thought better of it and I'm going to create a catch-all contact so I'll update all the communications.contact_ID with the new catch-all id. The problem is I have no idea how to go about that. what would the syntax be?
DELETE FROM Farm.tbl_communication
WHERE NOT EXISTS (
SELECT 1
FROM Farm.tbl_contacts
WHERE Farm.tbl_contacts.contact_ID = Farm.tbl_communication.contact_ID);
...or you can update them by changing the DELETE bit to UPDATE.

Complicated MySql Update Join Query

Have is an example of the problem I'm facing. The database tables are a little different than usual, but needed to be setup this way.
Items: id, order_id, other fields
Items_Drinks: id, drinks, other fields
Orders: id, other fields
Orders_Drinks: id, drinks, other fields
I need to have an update query that will update the Orders_Drinks table with the sum of the Items_Drinks drinks field that have the same order_id as Orders_Drinks id field.
Items: 1 1 ...
Items: 2 1 ...
Items_Drinks: 1 4 ...
Items_Drinks: 2 5 ...
Orders: 1 ...
Orders_Drinks: 1 9 ...
The Orders_Drinks is currently correct, but if I were to update Items_Drinks with id of 1 to 5, I would need an update command to get Orders_Drinks with id 1 to equal 10.
It would be best if the command would update every record of the Orders_Drinks.
I know my database is not typical, but it is needed for my application. This is because the Drinks table is not needed for all entries. The Drinks table has over 5000 fields in it, so if every record had these details the database would grow and slow for no real reason. Please do not tell me to restructure the database, this is needed.
I am currently using for loops in my C# program to do what I need, but having 1 command would save a ton of time!
Here is my best attempt, but it gives an error of "invalid group function".
update Orders_Drinks join Items on Items.order_id=Orders_Drinks.id join Items_Drinks on Items_Drinks.id=Items.id set Orders_Drinks.drinks=sum(Item_Drinks.drinks);
I think this is what you're wanting.
Edited:
UPDATE `Order_Drinks` a
SET a.`drinks` = (SELECT SUM(b.`drinks`) FROM `Items_Drinks` b INNER JOIN `Items` c ON (b.`id` = c.`id`) WHERE a.`id` = c.`order_id`)
That should give you a total of 9 for the Order_Drinks table for the row id of 1.
This is assuming that Orders.id == Orders_Drinks.id and that Items.id == Items_Drinks.id.
You need to do an aggregation. You can do this in the join part of the update statement:
update Orders_Drinks od join
(select i.order_id, sum(id.drinks) as sumdrinks
from Items i join
Items_Drinks id
on id.id = i.id
) iid
on iid.order_id = od.id
set od.drinks = iid.sumdrinks;
Something like this will return the id from the orders_drinks table, along with the current value of the drinks summary field, and a new summary value derived from the related items_drinks tables.
(Absent the name of the foreign key column, I've assumed the foreign key column names are of the pattern: "referenced_table_id" )
SELECT od.id
, od.drinks AS old_drinks
, IFNULL(td.tot_drinks,0) AS new_drinks
FROM orders_drinks od
LEFT
JOIN ( SELECT di.orders_drinks_id
, SUM(di.drinks) AS tot_drinks
FROM items_drinks di
GROUP BY di.orders_drinks_id
) td
ON td.orders_drinks_id = od.id
Once we have SELECT query written that gets the result we want, we can change it into an UPDATE statement. Just replace SELECT ... FROM with the UPDATE keyword, and add a SET clause, to assign/replace the value to the drinks column.
e.g.
UPDATE orders_drinks od
LEFT
JOIN ( SELECT di.orders_drinks_id
, SUM(di.drinks) AS tot_drinks
FROM items_drinks di
GROUP BY di.orders_drinks_id
) td
ON td.orders_drinks_id = od.id
SET od.drinks = IFNULL(td.tot_drinks,0)
(NOTE: the IFNULL function is optional. I just used it to substitute a value of zero whenever there are no matching rows in items_drinks found, or whenever the total is NULL.)
This will update all rows (that need to be updated) in the orders_drinks table. A WHERE clause could be added (after the SET clause), if you only wanted to update particular rows in orders_drinks, rather than all rows:
WHERE od.id = 1
Again, to get to this, first get a SELECT statement working to return the new value to be assigned to the column, along with the key of the table to be updated. Once that is working, convert it into an UPDATE statement, moving the expression that returns the new value down to a SET clause.