カーソルの結果を反復するループを実行しています。コードはトリガー関数内にあり、重要な部分は次のようになります。
[〜#〜] edit [〜#〜]:すみません、愚かな間違い。トリガーは、「one_table」で削除された後に実行されます。これは、トリガーのコード内で「削除」または「更新」操作を実行するのと同じテーブルではありません(下の2番目のリストを参照)
create trigger my_trigger after delete on one_table
for each row
begin
declare my_value int;
declare num_rows int default 0;
declare done int default false;
declare my_cursor cursor for select value from table where condition;
declare continue handler for sqlstate '02000' set done = 1;
open my_cursor;
select found_rows() into num_rows;
-- This is just for debugging
insert into log_table(key, value) values('foo', num_rows);
if num_rows > 0 then:
repeat
fetch my_cursor into my_value;
-- Do stuff
until done end repeat;
end if;
close my_cursor;
end
クエリは11個の値を返すため、ループは11回実行する必要があります。これは「挿入」句によってチェックされます。変数「num_rows」は11です。ただし、ループが3回しか実行されないことが問題です。
これらの数値(11、3)は重要ではありません。別の量の結果を返すようにクエリを変更すると、問題が残ります。ループはスケジュールされる前に終了します。
それは意味がありますか?ループの終了を引き起こすループ内(「do stuff」部分)で何かを行う場合があります。それは私にとって論理的に聞こえる唯一のものです。
[〜#〜] edit [〜#〜]:「Do stuff」の部分を含めます。この部分では、いくつかの「選択」文が実行されるため、問題が発生した可能性があります。これらの文のいずれかが空の結果を返すと、定義されたハンドラーが実行され、doneが「true」に設定されてループが解除されます。
「実行」の部分は次のとおりです。
select some_value into some_field from other_table where some_conditions;
if (some_field is null) then
delete from my_table where my_condition;
else
update my_table set key1 = value1 where condition1;
よろしくお願いいたします。
解決しました。前述のように、問題は内部の「SELECT INTO ...」文が0レコードを返し、CONTINUE HANDLERがトリガーされ、TRUEに設定されたことでした。 http://dev.mysql.com/doc/refman/5.0/en/cursors.html ( David Berganによる2012年2月23日午後10時のコメント)。
したがって、コードは最終的に次のようになります
create trigger my_trigger after delete on one_table
for each row
begin
declare my_value int;
declare num_rows int default 0;
declare done int default false;
declare my_cursor cursor for select value from table where condition;
declare continue handler for not found set done = true;
open my_cursor;
my_loop: loop
set done = false;
fetch my_cursor into my_value;
if done then
leave my_loop;
end if;
select some_value into some_field from other_table where some_conditions;
if (some_field is null) then
delete from my_table where my_condition;
else
update my_table set key1 = value1 where condition1;
end if;
end loop my_loop;
close my_cursor;
end
RolandoMySQLDBAの回答に感謝します。
ループ内のループの終了を厳密にチェックする必要があります
_create trigger my_trigger after delete on my_table
for each row
begin
declare my_value int;
declare num_rows int default 0;
declare done int default false;
declare my_cursor cursor for select value from table where condition;
declare continue handler for sqlstate '02000' set done = 1;
open my_cursor;
-- This is just for debugging
insert into log_table(key, value) values('foo', num_rows);
cursor_loop:repeat
if done then
leave cursor_loop;
end if;
fetch my_cursor into my_value;
-- Do stuff
until done
end repeat;
close my_cursor;
end
_
これにより、カウントをチェックする必要もなくなります
試してみる !!!
疑似コードを見る
_create trigger my_trigger after delete on my_table
for each row
begin
declare my_value int;
declare num_rows int default 0;
declare done int default false;
declare my_cursor cursor for select value from table where condition;
declare continue handler for sqlstate '02000' set done = 1;
open my_cursor;
-- This is just for debugging
insert into log_table(key, value) values('foo', num_rows);
cursor_loop:repeat
if done then
leave cursor_loop;
end if;
fetch my_cursor into my_value;
-- Do stuff
select some_value into some_field from other_table where some_conditions;
if (some_field is null) then
delete from my_table where my_condition;
else
update my_table set key1 = value1 where condition1;
until done
end repeat;
close my_cursor;
end
_
同じテーブルのafter UPDATE
トリガーの真ん中にいるときに、my_tableでDELETE
を実行することはお勧めできません。また、同じテーブルのif (some_field is null) then
でDELETEを実行していることにも注意してください。
このトリガーをストアドプロシージャとして記述し、同じテーブルのDELETE内のテーブルのUPDATEをネストする代わりに、呼び出しを手動で使用する方がよいでしょう。