sql >> Base de Datos >  >> RDS >> Mysql

La mejor manera de evitar que un valor se vuelva negativo en mysql

No puedo decir nada sobre el rendimiento de la consulta, lo siento. Pero es posible que desee considerar factores desencadenantes para evitar que el caso de que el 'nuevo_saldo' se vuelva negativo. (Porque me parece extraño hacer una inserción nula en caso de que el 'nuevo_saldo' sea inferior a $cantidad, pero podría funcionar de todos modos :)).

Ver documentación de MySQL 5.0 para obtener detalles sobre cómo crear un disparador.

Básicamente, usted pondría el cheque, si NUEVO.nuevo_saldo es negativo en un ANTES-disparador. En caso afirmativo, entonces usaría una "ACCIÓN DE DETENCIÓN", un error deliberado en la ejecución, para abortar el desencadenador y la consulta INSERTAR. Ver ideas en la página mencionada en los comentarios.

Actualización:se modificó un poco (mi excusa para instalar MySQL en casa).

Mi versión tiene el problema de escribir una segunda vez en la base de datos para cada valor ingresado en moneylog.

Tal vez sería aconsejable cambiar a un proceso almacenado. O alguien más tiene una idea mejor, no estoy muy interesado en DB :)

CREATE DATABASE triggertest;
CONNECT triggertest;

CREATE TABLE transferlog (
  account SMALLINT UNSIGNED NOT NULL ,
  amount INT NOT NULL,
  new_balance INT NOT NULL
) ENGINE=INNODB;

CREATE TABLE stopaction (
  entry CHAR(20) NOT NULL,
  dummy SMALLINT,
  UNIQUE(`entry`)
);

INSERT INTO stopaction (`entry`) VALUES ('stop');

DELIMITER #
CREATE TRIGGER nonneg_insert BEFORE INSERT ON transferlog
  FOR EACH ROW BEGIN
    INSERT INTO stopaction (`entry`)
      SELECT CASE WHEN NEW.new_balance<0 THEN 'stop'
                  ELSE 'none' END;
    DELETE FROM stopaction WHERE entry!='stop';
  END;
#

CREATE TRIGGER nonneg_update BEFORE UPDATE ON transferlog
  FOR EACH ROW BEGIN
    INSERT INTO stopaction (`entry`)
      SELECT CASE WHEN NEW.new_balance<0 THEN 'stop'
                  ELSE 'none' END;
    DELETE FROM stopaction WHERE entry!='stop';
  END;
#
DELIMITER ;


INSERT INTO transferlog (`account`, `amount`, `new_balance`)  
  VALUES (1, 1000, 1000);
INSERT INTO transferlog (`account`, `amount`, `new_balance`)
  VALUES (1, -1000, 0);
INSERT INTO transferlog (`account`, `amount`, `new_balance`)
  VALUES (1, -1000, -1000);
INSERT INTO transferlog (`account`, `amount`, `new_balance`)
  VALUES (1, 10, 20);
SELECT version();

DROP DATABASE triggertest;

Tal vez le convenga, mi resultado para INSERT-Lines es:

mysql> INSERT INTO transferlog (`account`, `amount`, `new_balance`)  VALUES (1, 1000, 1000);
Query OK, 1 row affected (0.03 sec)

mysql> INSERT INTO transferlog (`account`, `amount`, `new_balance`)  VALUES (1, -1000, 0);
Query OK, 1 row affected (0.02 sec)

mysql> INSERT INTO transferlog (`account`, `amount`, `new_balance`)  VALUES (1, -1000, -1000);
ERROR 1062 (23000): Duplicate entry 'stop' for key 1

mysql> INSERT INTO transferlog (`account`, `amount`, `new_balance`)  VALUES (1, 10, 20);
Query OK, 1 row affected (0.02 sec)

mysql> SELECT version();
+---------------------+
| version()           |
+---------------------+
| 5.0.67-community-nt |
+---------------------+
1 row in set (0.00 sec)