MSDE FunClub | 最終更新日 : 2000/08/21 | |
Microsoft Data Engine FunClub |
|
|
SQLServer7.0/MSDE 完全トレーニングテキスト(上巻) | ||
【第8章464p 〜 468p掲載】 |
-- [SQL08_03.SQL] -- SQLServer7.0 Transact-SQL言語 -- 日本技術ソフト開発 堀川 明 -- http://www.horikawa.ne.jp/msde/ -- -- このSQLプログラムは、 -- トリガ内部でROLLBACK命令を実行するものです -- -- この[社員]テーブルは、AccessのNorthwindデモデータベース -- の[社員]テーブルをSQLServerに転送したものです -- -- カレントデータベースを MySampleTest にする USE MySampleTest GO -- (件処理されました)のメッセージを抑止する SET NOCOUNT ON GO -- ********************************************************* -- 【社員】テーブルにトリガを組み込む -- 注意: -- 1)ROLLBACK命令を実行するときは、RAISERRORでメッセージ -- を出力すること -- 2)そのRAISERROR命令は、ROLLBACK命令の後で実行すること -- 3)外部変数@@ERRORは、直前のSQL文の実行結果を記憶する -- 4)ROLLBACKを正常に終えると、@@ERRORは 0 になります -- 5)だから、先にROLLBACK命令を実行して、その後でRAISERROR -- 命令を実行すれば、@@ERRORに RAISERRORのメッセージ番号 -- を入れることができる -- 6)この順番を間違えると、ダメ!! -- ********************************************************* IF( (object_id('TR_氏名CHK') IS NOT NULL) AND OBJECTPROPERTY(object_id('TR_氏名CHK') ,'IsTrigger' ) = 1 ) BEGIN DROP TRIGGER TR_氏名CHK END GO -- ///////////////////////////// CREATE TRIGGER TR_氏名CHK -- トリガの名前 -- ///////////////////////////// ON 社員 -- トリガを組み込むテーブル ----------- FOR INSERT -- 挿入時処理 ----------- AS SET NOCOUNT ON -- SELECT文のメッセージの抑止 --氏名欄に、'加藤 一郎'を入力したときはROLLBACKを実施する IF UPDATE(氏名) BEGIN IF EXISTS( SELECT 氏名 FROM inserted WHERE 氏名 = '加藤 一郎' ) BEGIN -- 入力されたので、違反とします -- 暗黙のトランザクションをロールバックする ROLLBACK TRANSACTION --メッセージ出力はROLLBACKの後にすること --外部@@ERRORに50000番が設定されます --ROLLBACKの前で実行すると、せっかく設定された50000番が --ROLLBACK命令自体の正常終了により、0 に戻される RAISERROR( '加藤一郎さんの入力はできません',16,1) RETURN END END GO -- ******************************* -- レコードの登録結果を表示 -- ******************************* IF( (object_id('P_挿入結果表示') IS NOT NULL) AND OBJECTPROPERTY(object_id('P_挿入結果表示') ,'IsProcedure' ) = 1 ) BEGIN DROP PROCEDURE P_挿入結果表示 END GO -- ///////////////////////////// CREATE PROCEDURE P_挿入結果表示 -- ///////////////////////////// AS DECLARE @社員コード int , @フリガナ varchar(20) , @氏名 varchar(20) DECLARE @Str社員コード varchar(4) , @strout varchar(80) DECLARE hC INSENSITIVE CURSOR FOR SELECT 社員コード,フリガナ,氏名 FROM 社員 WHERE( 社員コード BETWEEN 10 AND 20 ) -- カーソルを開いてレコードを表示する OPEN hC -- レコードはありますか? IF( @@CURSOR_ROWS = 0 ) BEGIN PRINT '*** レコードは存在しません ***' PRINT ' レコード登録に失敗!! ' GOTO L9999 END -- タイトル行の出力 EXEC master..xp_sprintf @strout OUTPUT , '[%.2s][%12s][%12s]' , 'NO' , 'フリガナ' , ' 氏 名 ' PRINT '' PRINT '**** 登録結果 ****' PRINT @strout -- 先頭行の取り出し FETCH NEXT FROM hC INTO @社員コード,@フリガナ,@氏名 -- 0の時は、正常に取得できました WHILE( @@FETCH_STATUS = 0 ) BEGIN -- 取り出し内容の編集とその出力 SELECT @Str社員コード = CONVERT(char(4),@社員コード) EXEC master..xp_sprintf @strout OUTPUT , '[%.2s][%12s][%12s]' , @Str社員コード , @フリガナ , @氏名 PRINT @strout -- 次行の取り出し FETCH NEXT FROM hC INTO @社員コード,@フリガナ,@氏名 END L9999: -- カーソルを閉じて破棄する CLOSE hC DEALLOCATE hC GO -- ********************************************************* -- 【トリガ違反を何も考慮しない場合】 -- トランザクション内でトリガ違反が発生します -- ********************************************************* DECLARE @TRI_ERR int SELECT @TRI_ERR = 1 -- =0:トリガ違反は発生しない -- =1:トリガ内部でROLLBACKを実行 PRINT '' PRINT '【トリガ内でROLLBACKが発生します(何も考慮しない場合)】' -- レコード挿入位置にレコードがあれば削除します DELETE FROM 社員 WHERE( 社員コード BETWEEN 10 AND 20 ) INSERT INTO 社員(社員コード,フリガナ,氏名) VALUES(10,'ヤマダ イチロウ' , '山田 一郎') INSERT INTO 社員(社員コード,フリガナ,氏名) VALUES(11,'ヤマダ ジロウ' , '山田 二郎') INSERT INTO 社員(社員コード,フリガナ,氏名) VALUES(12,'ヤマダ サブロウ', '山田 三郎') -- 1の時は、トリガ内部でROLLBACKが実行されます IF( @TRI_ERR = 1 ) INSERT INTO 社員(社員コード,フリガナ,氏名) VALUES(13,'カトウ イチロウ' , '加藤 一郎') IF( @@ERROR = 0 ) BEGIN PRINT 'レコード挿入でまったくエラーは起こりませんでした' EXEC P_挿入結果表示 END ELSE BEGIN --トリガの内部でROLLBACKすると、この命令は実行されない PRINT 'トリガ内部でROLLBACKを実行すると、そのバッチが強制終了します' PRINT 'この命令は実行されませんので注意しましょう!!' PRINT '結果表示を行なう次の命令も実行されません' END GO -- ******************************************************** -- 上記バッチ内でトリガ違反によるROLLBACKは発生しましたか? -- ******************************************************** -- トリガ内部で発生させたRAISERRORメッセージ番号です -- 自作メッセージは50000番になります IF( @@ERROR = 50000 ) BEGIN PRINT '' PRINT '*** レコード挿入処理で、トリガ違反が起こりました ***' -- 登録されたレコードを表示します EXEC P_挿入結果表示 END GO -- ********************************************************* -- 【トリガ違反を考慮する場合】 -- トランザクション内でトリガ違反が発生します -- ********************************************************* DECLARE @TRI_ERR int SELECT @TRI_ERR = 1 -- =0:トリガ違反は発生しない -- =1:トリガ内部でROLLBACKを実行 PRINT '' PRINT '【トリガ内でROLLBACKが発生します(全体をトランザクションで囲む)】' -- レコード挿入位置にレコードがあれば削除します DELETE FROM 社員 WHERE( 社員コード BETWEEN 10 AND 20 ) BEGIN TRANSACTION -- トランザクションの開始 INSERT INTO 社員(社員コード,フリガナ,氏名) VALUES(10,'ヤマダ イチロウ' , '山田 一郎') INSERT INTO 社員(社員コード,フリガナ,氏名) VALUES(11,'ヤマダ ジロウ' , '山田 二郎') INSERT INTO 社員(社員コード,フリガナ,氏名) VALUES(12,'ヤマダ サブロウ', '山田 三郎') IF(@TRI_ERR = 1 ) INSERT INTO 社員(社員コード,フリガナ,氏名) VALUES(13,'カトウ イチロウ' , '加藤 一郎') COMMIT TRANSACTION IF( @@ERROR = 0 ) BEGIN PRINT 'レコード挿入でまったくエラーは起こりませんでした' EXEC P_挿入結果表示 END ELSE BEGIN --トリガの内部でROLLBACKすると、この命令は実行されない PRINT 'トリガ内部でROLLBACKを実行すると、そのバッチが強制終了します' PRINT 'この命令は実行されませんので注意しましょう!!' PRINT '結果表示を行なう次の命令も実行されません' END GO -- ******************************************************** -- 上記バッチ内でトリガ違反によるROLLBACKは発生しましたか? -- ******************************************************** -- トリガ内部で発生させたRAISERRORメッセージ番号です -- 自作メッセージは50000番になります IF( @@ERROR = 50000 ) BEGIN PRINT '' PRINT '*** レコード挿入処理で、トリガ違反が起こりました ***' -- 登録されたレコードを表示します EXEC P_挿入結果表示 END GO