SQLのWHILE文で無限ループにはまった。
投稿の経緯
SQLでカーソルを使用して、カーソル内のデータについて処理する際に、
While文を用いて繰返し処理をしているのですが、そこで無限ループを起こしました
解決はしたものの、1時間以上つまずいくことに・・・
自戒を込めて原因と対処法について投稿します
※記事の間違い、もっと良いやり方があると言う方は教えていただけると嬉しいです
WHILE文とは
指定した条件が"True"を返す場合、処理を繰り返すことができる
基本構文は以下のとおりである
WHILE "条件式"
BEGIN
"繰り返したい処理"
TRY
WHILE "条件式" の下に繰返しの処理を"BEGIN"と"TRY"で書く。
このことを理解していれば、無限ループにはまることはなかっただろう。
環境
使用したDB
・SQL Sever Express 2016
※DBはサーバにあり、それをクライアントPCより操作していた。
無限ループが発生したWHILE文
以下が問題のSQLである。
目的の処理は
TableAからSelectした項目”A”をカーソルとして定義。(処理①)
定義したカーソルを開く(処理②)
処理①で取得したカーソルの1行目のデータをTableBへInesrtする(処理③)
ループ終了後、カーゾルを閉じて中身を消去する(処理④)
である。
--処理➀
DECLARE Cur CURSOR FOR
SELECT
A --カラム名
FROM
TableA
OPEN Cur --カーソルオープン
FETCH NEXT FROM Cur --処理➁
INTO
@a
--処理③
WHILE @@FETCH_STATUS = 0
--INSERT処理
BEGIN
INSERT INTO
TableB
(
A
)
VALUES
(
@a
)
END
BEGIN
FETCH NEXT FROM Cur
INTO
@a
;
END
END
CLOSE Cur--処理④
;
DEALLOCATE Cur
;
#結果
試しにSQLを実行してみたが、30分たっても終了しない
いくらカーソルを使用して繰り返しをしているとはいえ、
処理時間が長すぎる
そこで、無限ループしていることに気づいた
#原因
結論から言うとWhile文でループする範囲の指定を間違えたことにあった。
このSQLではWhileの下にあるBEGINがInsert文下のENDに対応しており、
次の行の取得がないため、
WHILE @@FETCH_STATUS = 0(カーソルの中身を取得できた場合0が返る)
を満たしつづけるため無限ループになっていた
--処理③
WHILE @@FETCH_STATUS = 0
--INSERT処理
BEGIN --ここから
INSERT INTO
TableB
(
A
)
VALUES
(
@a
)
END --ここまでループ
BEGIN
FETCH NEXT FROM Cur
INTO
@a
;
END
ので、正しくは以下の通りに BEGINとENDを
正しく指定すればよい
--処理③
WHILE @@FETCH_STATUS = 0
--INSERT処理
BEGIN --ここから
INSERT INTO
TableB
(
A
)
VALUES
(
@a
)
FETCH NEXT FROM Cur
INTO
@a
;
END --ここまでループ
#最後に
SQLを書く際には何も考えずに処理単位でBEGIN ENDを張っていたが
ちゃんと構文の形を理解しないと
思わぬところでハマると言う教訓になった出来事でした