teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

調整

2019/09/04 11:44

投稿

yambejp
yambejp

スコア117867

answer CHANGED
@@ -3,4 +3,75 @@
3
3
  普通のエラーがBで発生したら、不正終了するのが限界だと思います。
4
4
 
5
5
  以前の質問でこういうのがありました
6
- - [MYSQLで例外処理について](https://teratail.com/questions/108687)
6
+ - [MYSQLで例外処理について](https://teratail.com/questions/108687)
7
+
8
+
9
+ # sample
10
+
11
+ > Bの処理のデータ登録で処理が失敗
12
+
13
+ 失敗の種類によりますね
14
+ - [MySQL :: MySQL 5.6 リファレンスマニュアル :: B.3 サーバーのエラーコードおよびメッセージ](https://dev.mysql.com/doc/refman/5.6/ja/error-messages-server.html)
15
+
16
+ で、まず拾いたいエラーを確認します。
17
+
18
+ たとえば、tbl_bのプラマリー設定をして重複エラーになる場合
19
+ ```
20
+ エラー: 1062 SQLSTATE: 23000 (ER_DUP_ENTRY)
21
+ メッセージ: '%s' はキー %d で重複しています
22
+ ```
23
+ ということで"23000"を拾えば分岐に使えます。
24
+
25
+ - tbl_a,tbl_b作成
26
+ ```SQL
27
+ create table tbl_a(id int primary key auto_increment,val int);
28
+ insert into tbl_a values(1,100),(2,110),(3,120);
29
+ create table tbl_b(id int primary key,val int);
30
+ insert into tbl_b values(1,200),(2,210),(3,220);
31
+ ```
32
+
33
+ - まずproc_b作成
34
+ ```SQL
35
+ drop procedure if exists proc_b;
36
+ delimiter //
37
+ create procedure proc_b()
38
+ begin
39
+ insert into tbl_b values(4,430);
40
+ end
41
+ //
42
+ delimiter ;
43
+ ```
44
+ ※tbl_bに対してprimary keyを指定して投入します。
45
+ 今回はid=4なので、1回めは成功し、2回目以降は失敗します
46
+
47
+ - proc_aを作成
48
+
49
+ 上記踏まえproc_aを作成します
50
+ ```SQL
51
+ drop procedure if exists proc_a;
52
+ delimiter //
53
+ create procedure proc_a()
54
+ begin
55
+ declare done int default 0;
56
+ declare continue handler for sqlstate '23000' set done = 1;
57
+ call proc_b;
58
+ if done=0 then
59
+ insert into tbl_a(val) values(130);
60
+ end if;
61
+ end
62
+ //
63
+ delimiter ;
64
+ ```
65
+ ※命題ではトランザクションをロールバックするような記載でしたが
66
+ そもそもproc_bがエラーステータス23000を返してこないときだけ投入すればいいでしょう
67
+
68
+ # 実行
69
+ ```SQL
70
+ call proc_a;
71
+ ```
72
+ 1回目は成功するので、tbl_a,tbl_bそれぞれにレコードが1つずつ増えます。
73
+ 再度proc_aをコールします。
74
+ ```SQL
75
+ call proc_a;
76
+ ```
77
+ 2回目はproc_bが失敗するのでproc_aもinsert 処理をしません。