質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Q&A

解決済

1回答

2486閲覧

ストアドプロシージャ内でCALLしたストアドプロシージャの例外をキャッチする方法

shori0128

総合スコア29

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

0グッド

0クリップ

投稿2019/09/04 10:26

いつもお世話になっております。

タイトルの通りなのですが、Aというストアドプロシージャ内でBというストアドプロシージャをCALLした時、Bでエラーが発生した場合にA側で例外をキャッチすることは技術的に可能なのでしょうか?
調べてみたのですが、参考になりそうな文献が見つからず、技術的に可能なことをしようとしているのか不安になり質問した次第です。

A

1 DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING 2 BEGIN 3 GET DIAGNOSTICS CONDITION 1 4 @sqlstate = RETURNED_SQLSTATE, 5 @errno = MYSQL_ERRNO, 6 @text = MESSAGE_TEXT; 7 SIGNAL SQLSTATE '45000' 8 SET MESSAGE_TEXT = @text, 9 MYSQL_ERRNO = @errno; 10 ROLLBACK; 11 END; 12 13 〜何かの処理〜 14 15 # ↓この例外をキャッチしてエラーとしたい。 16 CALL B;

MySQLのバージョンは5.7です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

BのエラーとAでの掴み方次第でしょう
ロジカルなエラー(たとえばカーソルが一巡したみたいな)以外の
普通のエラーがBで発生したら、不正終了するのが限界だと思います。

以前の質問でこういうのがありました

sample

Bの処理のデータ登録で処理が失敗

失敗の種類によりますね

で、まず拾いたいエラーを確認します。

たとえば、tbl_bのプラマリー設定をして重複エラーになる場合

エラー: 1062 SQLSTATE: 23000 (ER_DUP_ENTRY) メッセージ: '%s' はキー %d で重複しています

ということで"23000"を拾えば分岐に使えます。

  • tbl_a,tbl_b作成

SQL

1create table tbl_a(id int primary key auto_increment,val int); 2insert into tbl_a values(1,100),(2,110),(3,120); 3create table tbl_b(id int primary key,val int); 4insert into tbl_b values(1,200),(2,210),(3,220);
  • まずproc_b作成

SQL

1drop procedure if exists proc_b; 2delimiter // 3create procedure proc_b() 4begin 5insert into tbl_b values(4,430); 6end 7// 8delimiter ;

※tbl_bに対してprimary keyを指定して投入します。
今回はid=4なので、1回めは成功し、2回目以降は失敗します

  • proc_aを作成

上記踏まえproc_aを作成します

SQL

1drop procedure if exists proc_a; 2delimiter // 3create procedure proc_a() 4begin 5declare done int default 0; 6declare continue handler for sqlstate '23000' set done = 1; 7call proc_b; 8if done=0 then 9insert into tbl_a(val) values(130); 10end if; 11end 12// 13delimiter ;

※命題ではトランザクションをロールバックするような記載でしたが
そもそもproc_bがエラーステータス23000を返してこないときだけ投入すればいいでしょう

実行

SQL

1call proc_a;

1回目は成功するので、tbl_a,tbl_bそれぞれにレコードが1つずつ増えます。
再度proc_aをコールします。

SQL

1call proc_a;

2回目はproc_bが失敗するのでproc_aもinsert 処理をしません。

投稿2019/09/04 10:33

編集2019/09/04 11:44
yambejp

総合スコア114843

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shori0128

2019/09/04 11:16

ご回答ありがとうございます。 Bの処理のデータ登録で処理が失敗したら、Aのデータ登録処理をロールバックしたいと考えています。 それをAの冒頭にある例外処理でキャッチしたいのですが、それは難しいということですか? ごく最近になってストアドプロシージャを使うようになったので、いまいち処理の内容が理解しきれていないので、見当違いな質問してるのかもしれないのですが、どうでしょうか? エラー自体は単純な不正エラーでキャッチ出来れば良いのですが。
yambejp

2019/09/04 11:45

今回のケースならエラーはキャッチできます。 サンプル追記しておいたので一度試してみてください
yambejp

2019/09/04 11:48

回答でお伝えした「普通のエラー」とはproc_b自体が構文エラーを 返して実行を失敗するとか、その手の話です
shori0128

2019/09/06 01:50

ありがとうございました!無事実現したい動作ができました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問