1

I am not sure, but I think I have an error in this query:

UPDATE product_discount SET price = '10,15' WHERE key_id = '1,2' 

I can't figure out why, but it only updates number 10 in the column and skips the 15.

Air
  • 8,274
  • 2
  • 53
  • 88

4 Answers4

4

I think this is what you need (Assuming Price should be 10 when key_id = 1):

UPDATE product_discount SET price = CASE WHEN key_id = 1 THEN 10 ELSE 15 END
WHERE key_id IN (1,2) 
Kaf
  • 33,101
  • 7
  • 58
  • 78
  • I'm not sure a `CASE` is required in there. – Radu Gheorghiu Mar 28 '14 at 17:00
  • 2
    If OP needs different values for `Price` depending on `key_id` then we need a CASE expression, otherwise not. As per his/her comments, I think OP needs 10 for key_id = 1. – Kaf Mar 28 '14 at 17:03
  • @Kaf, Your answer is great, I will do the same but I think the last WHERE part is not needed. – Rahul Mar 28 '14 at 17:12
  • This works for the specific case OP is asking about but it might be better to use explicit cases for each row that should be updated, instead of `ELSE 15`, in case novices don't immediately see how to extend this to update >2 rows. (Case in point: @Rahul's comment above...) – Air Mar 28 '14 at 17:12
2

You could try the method suggested in this answer:

INSERT INTO product_discount (key_id, price) 
VALUES (1, 10), (2, 15)
ON DUPLICATE KEY UPDATE price=VALUES(price);

Be sure to read the linked answer for some caveats, though; for example, this only works if:

  • There is a unique key constraint on key_id (e.g., it is the primary key)
  • You know that the rows with these ids already exist, or you don't mind inserting new rows if you provide an id that doesn't exist in the table

Despite these limitations on its use, the significant advantage of this method over CASE statements is much better readability and parameterization. In Python, for example, here's how you would execute the query given in @Kaf's answer using the MySQLdb module:

query = """UPDATE product_discount SET price = CASE 
    WHEN key_id = %s THEN %s ELSE %s 
    END 
WHERE ID IN (%s, %s);"""

params = (1, 10, 15, 1, 2)

cursor.execute(query, params)

How long is it going to take someone to figure out from that params tuple which values you want updated, and what their values should be? And what if you want to update more than two rows? Not only do you need to rewrite query for every use case of N rows, the params tuple becomes indecipherable garbage if N is anything more than a handful. You could write some helper functions to format both query and params according to the number of updates you need to do, but how long will that take? How easy will it be to understand? How many opportunities for bugs will you introduce in all these extra lines of code?

On the other hand, here's how you would do it using the INSERT ... ON DUPLICATE KEY UPDATE method:

query = """INSERT INTO product_discount (key_id, price) VALUES (%s, %s)
ON DUPLICATE KEY UPDATE price=VALUES(price);"""
params = [(1, 10),
          (2, 15),
          ]
cursor.executemany(query, params)

The key-value relationship is clear and highly readable. If more rows need to be updated, more key-value tuples can be added to the params list. It's not a perfect solution for every scenario, but it's a much better solution than CASE for particular (and I would argue, very common) scenarios.

Community
  • 1
  • 1
Air
  • 8,274
  • 2
  • 53
  • 88
  • 1
    @xQbert It's an `INSERT` statement, but an update method nonetheless. I've added some detail re: when and why you might prefer it over the `UPDATE ... CASE` method. – Air Mar 28 '14 at 18:10
  • 1
    Missed the `ON DUPLICATE KEY UPDATE price=VALUES(price);` initially. +1 for the follow through and more detail. The risk I see with this is if someone passes in the wrong parameters, you may end up updating an existing record when you really meant to create one; and no error would be thrown. While readability may improve, some environments may struggle with writing an insert statement for an update. but since the developer should see the `ON DUPLICATE KEY UPDATE price=VALUES(price);` risk is mitigated. to a degree. – xQbert Mar 28 '14 at 19:51
  • 1
    I think I would agree that the `UPDATE ... CASE` method is safer, in so far as can be made brutally explicit. The best thing would obviously be a supported syntax for multiple updates in MySQL. – Air Mar 28 '14 at 20:45
  • 1
    For that matter, [using a mapping table](http://stackoverflow.com/a/412323/2359271) is probably the safest and most scalable method, at the expense of requiring several extra steps. – Air Mar 28 '14 at 20:57
1

I think Kaf was close, but there are times where key_id can be 3 or 4 or 5 right? So you need to make sure those values don't change to 15. This should do the trick!

UPDATE product_discount 
SET price = CASE WHEN key_id = 1 THEN 10 
                 WHEN key_id = 2 THEN 15 
                 ELSE price END
King Decipher
  • 76
  • 1
  • 5
1

I feel what you are trying to do is

update price = 10 when key_id = 1
(OR)
price=15 when key_id = 2.

In that case just do it like

UPDATE product_discount SET price = 
CASE WHEN key_id = 1 THEN 10 
WHEN key_id = 2 THEN 15
ELSE price
END
Rahul
  • 76,197
  • 13
  • 71
  • 125
  • @JoachimIsaksson, My Bad totally. Thanks for pointing me the error. Update the answer and fiddle together. – Rahul Mar 28 '14 at 17:20
  • This should work, but I suspect if you have a few million rows, Kaf's answer will update only the rows necessary while this will update _all_ rows (or at least not use an index to find the rows to update) – Joachim Isaksson Mar 28 '14 at 17:33
  • So what will be the actual answer then @JoachimIsaksson cause I need it so much – user3465207 Mar 28 '14 at 19:36
  • @user3465207, I feel Kafs answer would be just fine for what you are asking. Only difference b/w Kaff's and my answer is the where clause. You can use the fiddle mentioned in this comment chain for testing purpose. – Rahul Mar 28 '14 at 19:41