sql >> Database teknologi >  >> RDS >> Mysql

Bedste måde at forhindre en værdi i at blive negativ i mysql

Jeg kan ikke sige noget om udførelsen af ​​forespørgslen, beklager. Men du vil måske overveje triggere for at forhindre, at tilfældet med 'new_balance' nogensinde bliver negativt. (Fordi det forekommer mig underligt at lave en null-indsættelse i tilfælde af, at 'new_balance' er lavere end $amount, men det virker måske alligevel :) ).

Se dokumentation af MySQL 5.0 for detaljer, hvordan man opretter en trigger.

Dybest set ville du sætte checken, hvis NEW.new_balance er negativ, i en FØR-trigger. Hvis ja, så ville du bruge en "STOP ACTION", en bevidst fejl i udførelsen, til at afbryde triggeren og INSERT-forespørgslen. Se ideer på den nævnte side i kommentarerne.

Opdatering:Fik lidt rundt (min undskyldning for at installere MySQL derhjemme).

Min version har problemet med at skrive en anden gang til DB for hver værdi, der er indtastet i pengeloggen.

Måske vil det være tilrådeligt at skifte til en lagret proc. Eller en anden har en bedre idé, jeg er ikke så meget til 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;

Måske vil det passe dig, mit output for INSERT-Lines er:

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)


  1. Er det muligt at bruge mysqli som databasedriver i Laravel?

  2. Python:MySQL:Håndtering af timeouts

  3. Nye Azure SQL Database Standard Tier Sizes

  4. Mysqli_error() virker ikke