sql >> データベース >  >> RDS >> Mysql

mysqlで値が負になるのを防ぐための最良の方法

    申し訳ありませんが、クエリのパフォーマンスについては何も言えません。ただし、「new_balance」が負になるのを防ぐためにトリガーを検討することをお勧めします。 ('new_balance'が$amountよりも低い場合にヌル挿入を行うのは奇妙だと思うので、それでも機能する可能性があります:))。

    MySQL5.0のドキュメント を参照してください。 トリガーの作成方法の詳細については、

    基本的に、NEW.new_balanceがBEFORE-triggerに負の場合、チェックを入れます。はいの場合は、実行中の意図的なエラーである「STOP ACTION」を使用して、トリガーとINSERTクエリを中止します。コメントで言及されたページのアイデアを参照してください。

    更新:少しいじくり回しました(自宅にMySQLをインストールするための私の言い訳)。

    私のバージョンでは、moneylogに入力された値ごとにDBに2回書き込むという問題があります。

    おそらく、ストアドプロシージャに切り替えることをお勧めします。または、他の誰かがより良いアイデアを持っています、私は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;
    

    多分それはあなたに合うでしょう、INSERT-Linesの私の出力は:

    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. sqlzooのチュートリアル#10に自己参加する

    2. MySQL-ツリー構造の再帰

    3. MariaDB USER()の説明

    4. 複数のテーブルからデータを選択しますか?