Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Najlepszy sposób, aby zapobiec wartości ujemnej w mysql

Nie mogę nic powiedzieć o wydajności zapytania, przepraszam. Możesz jednak rozważyć wyzwalacze, aby zapobiec sytuacji, w której „nowe_równowaga” stanie się ujemna. (Ponieważ wydaje mi się dziwne, że robię wstawkę zerową w przypadku, gdy 'new_balance' jest niższe niż $amount, ale mimo to może zadziałać :) ).

Zobacz dokumentację MySQL 5.0 aby uzyskać szczegółowe informacje na temat tworzenia wyzwalacza.

Zasadniczo umieściłbyś sprawdzenie, czy NEW.new_balance jest ujemna w funkcji BEFORE-trigger. Jeśli tak, użyjesz "ZATRZYMANIA AKCJI", celowego błędu w wykonaniu, aby przerwać wyzwalacz i zapytanie INSERT. Zobacz pomysły na wspomnianej stronie w komentarzach.

Aktualizacja:Trochę majstrowałem (moja wymówka do zainstalowania MySQL w domu).

Moja wersja ma problem z zapisaniem po raz drugi do DB dla każdej wartości wprowadzonej do moneylogu.

Może wskazane byłoby przejście na przechowywany proces. Albo ktoś inny ma lepszy pomysł, nie przepadam za 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;

Może to ci odpowiada, moje wyjście dla linii INSERT to:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. JDBC:klucz obcy na PK utworzony w tej samej transakcji

  2. jaki jest właściwy sposób konwersji między mysql datetime i python timestamp?

  3. MySql — czy klucz podstawowy jest domyślnie unikalny?

  4. Polecenia tworzenia kopii zapasowych i przywracania danych MySQL do administrowania bazą danych

  5. Jak wywołać procedury składowane MySQL z Perla?