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)