tags:

views:

316

answers:

4

I am coding and ran into a simple problem that I am sure there is a solution too - I just haven't been able to find it. I want to do the following query:

UPDATE `users` SET balance = (balance - 10) WHERE id=1

But if the balance will become a negative number I want an error to be returned. Any ideas on if this is possible?

Thank you,

Ice

+3  A: 

If you do

UPDATE `users` SET balance = (balance - 10) WHERE id=1 and balance >=10

You should be able to detect that a row was not modified.

Note that while another answer suggests using an unsigned int column, this may not work:

Create a test table

create table foo(val int unsigned default '0');
insert into foo(val) values(5);

Now we attempt to subtract 10 from our test row:

update foo set val=val-10;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 1

mysql> select * from foo;
+------------+
| val        |
+------------+
| 4294967295 |
+------------+

This was on mysql 5.0.38

Paul Dixon
Thank you Paul - I like your method - I'll return the amount of rows affected and if it is 0 I know the balance is to low.
Odd that the error is inconsistent. I'm getting it on 5.0.45
enobrev
+1  A: 

This sort of things is done by triggers. MySql have support for triggers only since 5.0.2.

DELIMITER $$
CREATE TRIGGER balance_check BEFORE INSERT ON user FOR EACH ROW
BEGIN
    IF new.balance < @limit_value THEN
        -- do something that causes error. 
        -- mysql doesn't have mechanism to block action by itself
    END IF;
END $$
DELIMITER ;

Triggers in MySql are quite rudimentary. You have to hack things around to do some things (e.g. cause error).

Slartibartfast
A: 

I dont think you can do this with a simple query. you should use a mysql user defined function that manage that before update the row. or a trigger

Gabriel Sosa
+2  A: 

You can make the balance field of the users table an unsigned int:

ALTER TABLE `users` CHANGE `balance` `balance` INT UNSIGNED;
Brian Fisher
You beat me to it by a few seconds. MySQL will return a "#1264 - Out of range value adjusted for column 'balance'" error for negative numbers on an unsigned field
enobrev
I didn't get that result:create table tmp2 (val int unsigned default '0');insert into tmp2(val)values(5);update tmp2 set val=val-10;select * from tmp2;+------------+| val |+------------+| 4294967295 |+------------+
Paul Dixon
hmm, difficult to read! suffice to say, when I subtract 10 from an unsigned int column containing 5, I get no error and a new value of 4294967295 on mysql 5.0.38
Paul Dixon
and if business logic changes to allow $100 debt, you are back at square one.
Slartibartfast
I have the same result as Paul Dixon - I also tried it before posting here
On my local instance of MySQL 5.0.67 I get a #1264 warning and it sets the value to 0.
Brian Fisher
This can result in the value wrapping around to a massive positive value. If this is dealing with money, that would be baaaad.
rikh