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

SUMでテーブルを更新

    トリガー おそらくあなたが欲しいです。ただし、これを適切かつ効率的に機能させるのは醜いでしょう。以前の日付の行を頻繁に挿入する場合は、各行に残高を保存しない方がよいでしょう。代わりに、クエリまたはビュー を使用してください バランスを見つけるために。特定の日付の残高を見つけるには、それを以前の日付の行と結合し、現在のトランザクションIDでグループ化して正味預金を合計します。

    CREATE VIEW pettybalance
      AS SELECT SUM(older.pc_in - older.pc_out) AS balance, 
                current.pc_id AS pc_id,  -- foreign key
                current.pc_date AS `date`
           FROM pettycash AS current
             JOIN pettycash AS older
               ON current.pc_date > older.pc_date 
                  OR (current.pc_date = older.pc_date AND current.pc_id >= older.pc_id)
           GROUP BY current.pc_id
    ;
    

    older.pc_idも制限します current.pc_id未満である スキーマとバランス計算に関連するあいまいさを修正するため。 pc_date以降 は一意ではありません。特定の日付に複数のトランザクションが発生する可能性があります。その場合、各トランザクションの残高はどのようになりますか?ここでは、IDが大きいトランザクションは、IDが小さいが、日付が同じであるトランザクションの後に発生すると想定しています。より正式には、順序付けを使用します

    ビューでは、>:

    に基づく≥の順序を使用していることに注意してください。

    トリガーを正しく機能させようとした後は、試さないことをお勧めします。挿入/更新時の内部テーブルまたは行ロックのため、残高列を新しいテーブルに移動する必要がありますが、これはそれほど面倒ではありません(pettycashの名前を変更してください)。 pettytransactionsへ 、新しいpettybalance (balance, pc_id)を作成します テーブルを作成し、pettycashという名前のビューを作成します pettytransactionsに参加するより およびpettybalance pc_idで )。主な問題は、トリガー本体が作成または更新された行ごとに1回実行されるため、非常に非効率になることです。別の方法は、ストアドプロシージャ を作成することです。 列を更新します。これは、挿入または更新後に呼び出すことができます。残高を取得する場合、プロシージャはビューよりもパフォーマンスが高くなりますが、データベースに処理させるのではなく、プログラマーが残高を更新する必要があるため、より脆弱になります。ビューを使用すると、よりすっきりとしたデザインになります。

    DROP PROCEDURE IF EXISTS update_balance;
    delimiter ;;
    CREATE PROCEDURE update_balance (since DATETIME)
    BEGIN
        DECLARE sincebal DECIMAL(10,2);
        SET sincebal = (
              SELECT pc_bal 
                FROM pettycash AS pc 
                WHERE pc.pc_date < since
                ORDER BY pc.pc_date DESC, pc.pc_id DESC LIMIT 1
            );
        IF ISNULL(sincebal) THEN
          SET sincebal=0.0;
        END IF;
        UPDATE pettycash AS pc
          SET pc_bal=(
            SELECT sincebal+SUM(net) 
              FROM (
                SELECT pc_id, pc_in - pc_out AS net, pc_date
                  FROM pettycash
                  WHERE since <= pc_date 
              ) AS older
              WHERE pc.pc_date > older.pc_date
                 OR (pc.pc_date = older.pc_date 
                     AND pc.pc_id >= older.pc_id)
          ) WHERE pc.pc_date >= since;
    END;;
    delimiter ;
    

    オフトピック

    現在のスキーマの問題は、Floatの使用です。 ■金銭的価値を保存します。浮動小数点数の表現方法が原因で、基数10で正確な(つまり、循環小数表現がない)数値は、常に浮動小数点数として正確であるとは限りません。たとえば、0.01(10進数)は、保存すると0.009999999776482582...または0.0100000000000000002081668...に近くなります。基数3の1/3は「0.1」ですが、基数10では0.333333....に似ています。Floatの代わりに 、Decimal タイプ:

    ALTER TABLE pettycash MODIFY pc_in DECIMAL(10,2);
    ALTER TABLE pettycash MODIFY pc_out DECIMAL(10,2);
    

    ビューを使用している場合は、pettycash.pc_balをドロップします 。ストアドプロシージャを使用してpettycash.pc_balを更新する場合 、それも変更する必要があります。




    1. CodeIgniterPHPでDBエラーをキャッチする方法

    2. PostgresSQL集計クエリのパフォーマンスを向上させる

    3. SQLServerでの1対0または1の関係の実装

    4. ネットワークが不安定なときにDB接続が失敗しないようにするにはどうすればよいですか?