Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Cara terbaik untuk mencegah nilai menjadi negatif di mysql

Saya tidak bisa mengatakan apa-apa tentang kinerja kueri, maaf. Tetapi Anda mungkin ingin mempertimbangkan pemicu untuk mencegah kasus 'new_balance' menjadi negatif. (Karena menurut saya aneh untuk melakukan penyisipan nol jika 'new_balance' lebih rendah dari $amount, tetapi mungkin berhasil :)).

Lihat dokumentasi MySQL 5.0 untuk detail cara membuat pemicu.

Pada dasarnya Anda akan memberi tanda centang, jika NEW.new_balance negatif ke pemicu SEBELUM. Jika ya, maka Anda akan menggunakan "STOP ACTION", kesalahan yang disengaja dalam eksekusi, untuk membatalkan pemicu dan kueri INSERT. Lihat ide di halaman yang disebutkan di komentar.

Pembaruan:Sedikit mengutak-atik (alasan saya untuk menginstal MySQL di rumah).

Versi saya memiliki masalah untuk menulis kedua kalinya ke DB untuk setiap nilai yang dimasukkan ke dalam moneylog.

Mungkin beralih ke proc yang tersimpan akan disarankan. Atau orang lain punya ide yang lebih baik, saya tidak terlalu suka 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;

Mungkin cocok untuk Anda, output saya untuk INSERT-Lines adalah:

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. Doctrine 2 Query Builder abs Fungsi

  2. Ubah format output untuk hasil baris perintah MySQL ke CSV

  3. Tabel data yang bergabung dengan tabel pencarian dan pesanan terjebak dengan codeigniter

  4. Bagaimana cara melakukan otentikasi di node.js yang dapat saya gunakan dari situs web saya?

  5. Dapatkan semua objek tanpa loop di OOP MySQLi