Mysql Update statement to delete duplicates - mysql

I would like to make an update on my unique id like replacing white space, but on that case the update statement breaks because of redundant s I tried to make an update as it follows but
wrong syntax
UPDATE __cat_product
SET product_id = REPLACE(product_id,' ','')
ON DUPLICATE KEY DELETE product_id
WHERE product_id LIKE "%A %"
how to do this in the right way?

There is no ON DUPLICATE KEY syntax that is part of an UPDATE statement.
I'm having difficulty figuring out what you actually want to do.
You want to update a column in a table, to remove all space characters. And when you tried to run that statement, the statement encountered an error like Duplicate entry 'foo' for key 'PRIMARY'.
Assuming that product_id is varchar, try this on for size:
UPDATE __cat_product t
JOIN ( SELECT MAX(s.product_id) AS product_id
, REPLACE(s.product_id,' ','')
FROM __cat_product s
WHERE s.product_id LIKE '%A %'
AND NOT EXISTS ( SELECT 1
FROM __cat_product d
WHERE d.product_id = REPLACE(s.product_id,' ','')
)
GROUP BY REPLACE(s.product_id,' ','')
) r
ON r.product_id = t.product_id
SET t.product_id = REPLACE(t.product_id,' ','')
The inline view aliased as r gets the values of product_id that can actually be updated, because the "updated" product_id value doesn't already exist in the table. And the GROUP BY ensures that we're only getting one product_id per targeted replacement value.
There may be rows in the table that still match the predicate product_id LIKE '%A %'. The spaces cannot be removed from product_id column on those rows without throwing a duplicate key exception.
A separate DELETE statement could be used to remove those rows.

Related

MYSQL Query generating multiplication of existing value in table

i am trying to do a mysql query to update a table with some values in order of ID, i have sucess in the first time (generate 38 result row) but when i execute this again, this multiplicate the existing value in the table (38x38 = 1444 row result) repeting the already existing product_id in new ID rows.....
i want to insert to this table, only unique product_id from the another target table, and group by the ID [1,2,3,4,5, and dont repeat this too]
the code:
/* add all eligible customers to temporary table */
INSERT INTO `temp_wp_woocommerce_subscription_downloads`
(`product_id`, `subscription_id`)
SELECT posts.ID AS product_id, downn.subscription_id AS subscription_id
FROM wp_posts posts
JOIN wp_woocommerce_subscription_downloads downn
WHERE posts.post_type = 'product'
AND posts.post_status = 'publish'
;
in the print you can see the generated issue:
(https://prntscr.com/s2zhil)
EDIT: Work perfect with the code from the #GordonLinoff answer,but after run and add a new product and run the query again the ID is dont by a order (appear to "jump/burn some ids", how i order by unique id's too? and as you can see :
http://prntscr.com/s31rrq
This addresses the original version of the question.
You can add a unique index on productid and then use on duplicate key.
alter table temp_wp_woocommerce_subscription_downloads
add constraint unq_temp_wp_woocommerce_subscription_downloads_product_id
unique(product_id);
INSERT INTO temp_wp_woocommerce_subscription_downloads(`product_id`, `subscription_id`)
SELECT p.ID AS product_id, d.subscription_id AS subscription_id
FROM wp_posts posts p JOIN
wp_woocommerce_subscription_downloads d
ON p.post_type = 'product' AND p.post_status = 'publish'
ON DUPLICATE KEY UPDATE subscription_id = d.subscription_id;
That said, I suspect that you might also be missing a JOIN condition on the table -- say by post or product.

Insert, select & ON Duplicate KEY

i'am always getting syntax error when execute this query. Any Ideas what i'm doing wrong?
INSERT INTO cookies (cookie, buy, orders, ordervalue) SELECT o.uid cookie, 'eby' as a, COUNT(o.price ) as b , ROUND( SUM(o.price) , 2 ) umsatz
FROM `Orders` o
WHERE uid != ''
GROUP BY uid ON DUPLICATE KEY UPDATE buy=VALUES(a), orders=VALUES(b);
I'm not sure ift its possible to use alias in "on duplicate". I ve tried also to calculate the values again in the "on duplicate" part. But also get an error.
The problem is here:
... UPDATE buy=VALUES(a), orders=VALUES(b)
^ ^
a and b aren't valid in this context. Reference the name of the column in the column list of the INSERT to get the value that would have been inserted into that column (if the insert had succeeded)
... UPDATE buy=VALUES(buy), orders=VALUES(orders)
^^^ ^^^^^^
(It doesn't matter if the expressions in the SELECT have aliases or not; it's not valid to reference expressions from the SELECT in the ON DUPLICATE KEY clause.

MySQL: How can I make this subquery work while updating a value?

I'm trying to write a query that lists an Item ID, Title, old price, and new price. I can't do an update statement because then I don't think I could list the old price.
INSTRUCTION:
USE A SUBQUERY to Increase price of all items by ‘No Rest for the Weary’ by 10%. Show prices before and after. Rollback after.
There are three main goals to this assignment based on instruction:
1. Show old price.
2. Show new price through calculation using a subquery.
3. Use a rollback once finished.
Questions:
Is it possible to put an UPDATE inside of a SELECT statement like a subquery?
(Answer is apparently no.)
Where I've run into issue:
UPDATE items
SET unit_price = ROUND(unit_price + (unit_price * .10),2) as 'New Price'
WHERE item_id =
(SELECT item_id as 'Item ID',
title as 'Title',
unit_price as 'Old Price', --Except this won't work because the unit price is now the new price...
FROM items
WHERE title = 'No Rest for the Weary'
);
This is what I have now, but the ROLLBACK bit has me stuck. Where would one put that in this situation? Or have I misunderstood the instructions entirely?
SELECT item_id as 'Item ID', title as 'Title', unit_price as 'Price',
ROUND(unit_price + (unit_price * .10),2) as 'New Price'
FROM items
WHERE item_id =
(SELECT item_id
FROM items
WHERE title = 'No Rest for the Weary'
);
No, it's not possible to include an UPDATE statement within a SELECT statement. But it is possible to include a SELECT inside an UPDATE.
Why do you need an UPDATE statement? Is the intent to update a column in a table with a new value, so the new value is persisted?
Or, is the intent to return a resultset? An UPDATE statement doesn't return a resultset like a SELECT statement does.
The UPDATE statement in the question won't work, because there are three columns being returned by the subquery. Used in the context
col IN (subquery)
The subquery should return only one column. It's invalid to return two or more columns.
You can write a SELECT statement that returns the result of an expression. In this example, a new unit price as a 10% increase over the current unit_price...
SELECT i.item_id AS `item_id`
, i.title AS `title`
, i.unit_price AS `old_unit_price`
, ROUND(i.unit_price*1.1,2) AS `new_unit_price`
FROM items i
WHERE i.title = 'No Rest for the Weary'
ORDER BY i.item_id
If that's return the result you want, and you want to use that in an UPDATE to assign a new value to the unit_price column, assuming item_id is the PRIMARY or UNIQUE KEY on the items table...
UPDATE ( SELECT r.*
FROM ( -- select statement above goes here
SELECT i.item_id AS `item_id`
, i.title AS `title`
, i.unit_price AS `old_unit_price`
, ROUND(i.unit_price*1.1,2) AS `new_unit_price`
FROM items i
WHERE i.title = 'No Rest for the Weary'
) r
) s
JOIN items t
ON t.item_id = s.item_id
SET t.unit_price = s.new_unit_price
Again, to emphasize the point, this assumes that item_id is the PRIMARY KEY (or a non-NULL UNIQUE KEY) on the items table.
Following the UPDATE statement, re-running the original SELECT query will return different results (assuming the original unit_price was sufficiently greater than zero.)
FOLLOWUP
Create query that shows old price
The first SELECT in the answer above shows the "old price" (assuming that the "old price" is stored in the unit_price column.)
Change the price to 10% more than the current price.
The first SELECT in the answer above shows adding 10% to the unit_price column, rounded to two digits after the decimal point, returned as another column new_unit_price.
Use a subquery
The first query doesn't use a subquery. But we could easily add one. (I'm not understanding why we need to add an unnecessary subquery. Does it matter what that subquery returns, can we use a subquery in the SELECT list, or in the WHERE clause, does an inline view qualify as a subquery?)
This version adds two unnecessary correlated subqueries to the SELECT list, an unnecessary inline view, and an unnecessary subquery in the WHERE clause.
SELECT i.item_id AS `item_id`
, ( SELECT t.title
FROM items t
WHERE t.item_id = i.item_id
ORDER BY t.title
LIMIT 1
) AS `title`
, ( SELECT p.unit_price
FROM items p
WHERE p.item_id = i.item_id
ORDER BY p.unit_price
LIMIT 1
) AS `old_unit_price`
, ROUND(i.unit_price*1.1,2) AS `new_unit_price`
FROM items i
CROSS
JOIN ( SELECT 1 AS i ) i
WHERE i.title = (SELECT 'No Rest for the Weary')
ORDER BY i.item_id
A simpler version of the UPDATE statement (to add 10% to unit_price) also doesn't require a subquery.
UPDATE items t
SET t.unit_price = ROUND(t.unit_price*1.1,2)
WHERE t.title = 'No Rest for the Weary'
Again, it's not possible for an UPDATE statement to return a resultset.

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.

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.