MSDE FunClub | 最終更新日 : 2000/08/17 | |
Microsoft Data Engine FunClub |
|
|
SQLServer7.0/MSDE 完全トレーニングテキスト(上巻) | ||
【第6章354p 〜 357p掲載】 |
-- [SQL06_03.SQL] -- SQLServer7.0 Transact-SQL言語 -- 日本技術ソフト開発 堀川 明 -- http://www.horikawa.ne.jp/msde/ -- -- このSQLプログラムは、 -- トリガを利用して在庫個数と販売個数を管理する例題です。 -- 商品を販売したら在庫個数を減らします。ただ在庫個数が -- 負になる場合の入力はトリガで違反とします。 -- この例題は、簡単に考えるため1レコード単位で更新命令 -- が発行されるものとする -- -- 【注意】 -- ROLLBACKとRAISERRORを実行するときは、ROLLBACKを先に -- 実行します -- エラーメッセージ番号を伝播させるためです -- ROLLBACKが行われると @@ERRORは 0 に戻されます -- -- カレントデータベースを MySampleTest にする USE MySampleTest GO -- (件処理されました)のメッセージを抑止する SET NOCOUNT ON GO -- ************************************************* -- 見本テーブルの作成 -- ************************************************* -- 既存テーブルが存在したら削除します IF( (object_id('T_在庫') IS NOT NULL) AND OBJECTPROPERTY( object_id('T_在庫'),'ISTABLE') = 1 ) BEGIN PRINT 'T_在庫 テーブルが存在したので削除しました' DROP TABLE T_在庫 END GO -- 新しくテーブルを作成する CREATE TABLE T_在庫 ( -- 主キー ID int CONSTRAINT PK_T_在庫 PRIMARY KEY , -- 商品番号 -- 在庫データです ZAIKO_DATA int ) GO -- 既存テーブルが存在したら削除します IF( (object_id('T_販売') IS NOT NULL) AND OBJECTPROPERTY( object_id('T_販売'),'ISTABLE') = 1 ) BEGIN PRINT 'T_販売 テーブルが存在したので削除しました' DROP TABLE T_販売 END GO -- 新しくテーブルを作成する CREATE TABLE T_販売 ( -- 主キー(連番) IDROW int IDENTITY(1,1) CONSTRAINT PK_T_販売 PRIMARY KEY , -- 商品番号 ID int , -- 販売個数 HANBAI_DATA int ) GO -- ************************************************* -- トリガの登録 -- 挿入と更新処理を行う -- ************************************************* CREATE TRIGGER TR_販売検査 -- トリガの名前 ON T_販売 -- トリガを組み込むテーブル ----------- FOR UPDATE,INSERT ----------- AS DECLARE @入力後個数 int DECLARE @入力前個数 int DECLARE @増加 int DECLARE @ID int --レベルは1です --すでにトランザクションが開始されています --PRINT 'トリガ開始直後のトランザクションレベル = ' + CAST(@@TRANCOUNT AS char) -- SELECT文のメッセージを抑止する SET NOCOUNT ON -- このトリガは1レコードしか対応しません IF (SELECT COUNT(IDROW) FROM inserted) <> 1 BEGIN ROLLBACK TRANSACTION -- 変更を元に戻す RAISERROR('T_販売 テーブルは複数レコード同時操作禁止',16,1) RETURN -- トリガの終了 END -- 個数を求める SELECT @入力前個数 = 0 -- 初期値代入をしておくこと SELECT @入力前個数 = ISNULL(HANBAI_DATA,0) FROM deleted SELECT @入力後個数 = ISNULL(HANBAI_DATA,0) , @ID = ID FROM inserted --RAISERROR('@入力前個数=%d @入力後個数=%d @ID=%d' , 0,1 , -- @入力前個数 , @入力後個数 , @ID ) WITH NOWAIT -- IDがT_在庫に登録されていなければ致命的エラーです IF NOT EXISTS(SELECT ID FROM T_在庫 WHERE ID = @ID) BEGIN ROLLBACK TRANSACTION RAISERROR('ID=%d は、T_在庫 では未登録です', 16,1,@ID) RETURN END -- 個数には変化ありません IF (@入力前個数 = @入力後個数) BEGIN --RAISERROR('入力個数に変化はありませんでした(終了)',0,1) WITH NOWAIT RETURN END -- 在庫個数調査が必要です IF( @入力前個数 < @入力後個数 ) BEGIN --PRINT '在庫引き算が必要です' SELECT @増加 = @入力後個数 - @入力前個数 --RAISERROR('@入力前個数=%d @入力後個数=%d @増加=%d',0,1, -- @入力前個数,@入力後個数,@増加) WITH NOWAIT -- @増加分を在庫から試しに引き算します -- 但しトランザクションを作ります -- 注意:トリガ内部は暗黙のトランザクションが開始されているので、この -- BEGIN TRANの命令は不要です -- 勉強のため、入れました BEGIN TRANSACTION UPDATE T_在庫 SET ZAIKO_DATA = ZAIKO_DATA - @増加 WHERE (ID = @ID) --在庫が負になっていたら、中止する IF (SELECT ZAIKO_DATA FROM T_在庫 WHERE (ID = @ID) ) < 0 BEGIN -- 外側のトランザクションまで中止されます ROLLBACK TRANSACTION RAISERROR('在庫個数が負になるため、中止します',16,1) RETURN END -- 更新できました --RAISERROR('在庫個数の更新ができました',0,1)WITH NOWAIT --BEGIN TRAN 同様、このCOMMIT TRANは不要です COMMIT TRANSACTION --PRINT 'トランザクションレベル = ' + CAST(@@TRANCOUNT AS char) RETURN END -- 在庫個数を増やす必要があります -- 恐らく入力ミスで同じ場所で2回も入力操作を行ったのでしょう SELECT @増加 = @入力前個数 - @入力後個数 UPDATE T_在庫 SET ZAIKO_DATA = ZAIKO_DATA + @増加 WHERE (ID = @ID) RETURN GO -- テスト --- INSERT INTO T_在庫 values(1,10) GO INSERT INTO T_販売(ID,HANBAI_DATA) values(1,3) SELECT * FROM T_在庫 GO