MySQL テーブルのすべての行をループする
- MySQL テーブルのすべての行をループする
-
ストアド プロシージャで
WHILEループを使用して、MySQL テーブルのすべての行をループする -
ストアド プロシージャで
CURSORを使用して、MySQL テーブルのすべての行をループする -
WHILEとCURSORの使い方の比較
今日は、ストアド プロシージャで WHILE と CURSOR を使用して、MySQL テーブルのすべての行をループする方法について学習します。 また、各手法の長所と短所を調べて、どの状況に適しているかを区別します。
MySQL テーブルのすべての行をループする
特定のテーブルまたは複数のテーブルからデータを読み取り/挿入するために、MySQL テーブルのすべての行をループするために使用できるさまざまなアプローチについて学習します。 コード例でそれぞれを学びましょう。
そのために、employees と emp_performance の 2つのテーブルがあります。 employees テーブルには、属性として EMP_ID、FIRSTNAME、LASTNAME、GENDER、および AGE があります (列名とも呼ばれます)。
emp_performance テーブルには PERFORM_ID、FIRSTNAME、LASTNAME、および PERFORMANCE フィールドがあり、FIRSTNAME と LASTNAME は employees テーブルと同じです。
employees テーブルから FIRSTNAME と LASTNAME をコピーし、emp_performance テーブルに挿入して、毎月各従業員の PERFORMANCE を計算する必要があると想像してみてください。
employees テーブルから必要な値を SELECT し、INSERT を emp_performance テーブルに保存し、後で PERFORMANCE の計算を続行する方法が必要です。 employees と emp_perfomance を作成して続行することもできます。 コードを以下に示します。
コード例:
#create an `employees` table
CREATE TABLE employees (
EMP_ID INT NOT NULL AUTO_INCREMENT,
FIRSTNAME VARCHAR(45) NOT NULL,
LASTNAME VARCHAR(45) NOT NULL,
GENDER VARCHAR(45) NOT NULL,
AGE INT NOT NULL,
PRIMARY KEY (EMP_ID));
#insert data
INSERT INTO employees (FIRSTNAME, LASTNAME, GENDER, AGE) VALUES
('Mehvish','Ashiq', 'Female', 30),
('Thomas', 'Christopher', 'Male', 22),
('John', 'Daniel', 'Male', 34),
('Saira', 'James', 'Female', 27);
#create a `emp_performance` table
CREATE TABLE emp_performance (
PERFORM_ID INT NOT NULL AUTO_INCREMENT,
FIRSTNAME VARCHAR(45) NOT NULL,
LASTNAME VARCHAR(45) NOT NULL,
PERFORMANCE VARCHAR(45) NULL,
PRIMARY KEY (PERFORM_ID));
ストアド プロシージャで WHILE と CURSOR を使用して、employees テーブルのすべての行をループし、INSERT を emp_performance テーブルに入れることができます。
ストアド プロシージャで WHILE ループを使用して、MySQL テーブルのすべての行をループする
これで、テーブルの準備が整いました。 したがって、次の手順を記述して実行し、employees テーブルから FIRSTNAME と LASTNAME を SELECT し、INSERT を emp_performance テーブルに挿入できます。
コード例:
DROP PROCEDURE IF EXISTS CALCPERFORMANCE;
DELIMITER ;;
CREATE PROCEDURE CALCPERFORMANCE()
BEGIN
DECLARE length INT DEFAULT 0;
DECLARE counter INT DEFAULT 0;
SELECT COUNT(*) FROM employees INTO length;
SET counter=0;
WHILE counter<length DO
INSERT INTO emp_performance(FIRSTNAME, LASTNAME)
SELECT FIRSTNAME, LASTNAME FROM employees LIMIT counter,1;
SET counter = counter + 1;
END WHILE;
End;
;;
DELIMITER ;
CALL CALCPERFORMANCE();
レコードが挿入されたら、SELECT コマンドを使用して emp_performance 出力を確認します。
SELECT * from emp_performance;
出力 (WHILE ループを使用した emp_performance テーブル):
PERORM_ID |
FIRSTNAME |
LASTNAME |
PERFORMANCE |
|---|---|---|---|
| 1 | メーヴィシュ | アシク | ヌル |
| 2 | トーマス | クリストファー | ヌル |
| 3 | ジョン | ダニエル | ヌル |
| 4 | さいら | ジェームズ | ヌル |
CALCPERFORMANCE ストアド プロシージャを実行すると、PERFORM_ID、FIRSTNAME、および LASTNAME のみが入力されます。
行番号を使用したコードの説明
- 行 1 は、
CALCPERFORMANCEという名前で作成済みのプロシージャを削除します。 - 行 2 は、デフォルトの delimiter を
;;に変更します。 このように、特定のタスクを達成するためのプロシージャを作成しようとしているため、SQL はすべての行を実行するわけではありません。 - 行 4 は、提供されたプロシージャー名を使用してプロシージャーを作成します。
- この手順に必要なすべてのステートメントは、5 行目と 15 行目の間に記述されます。
- 5 行目で手順を開始します。
- 6 行目と 7 行目は、
DEFAULT値がそれぞれ 0 と 0 であるINT型のlengthとcounterという名前の変数を宣言します。 - 8 行目では、
employeesテーブルからカウントをSELECTし、その値をlength変数に代入します。 - 9 行目で
counterに 0 を設定します。 - 10 行目から 14 行目には、
employeesテーブルからFIRSTNAMEとLASTNAMEをSELECTし、emp_performanceテーブルにINSERTするWHILEループがあります。 各反復で 1つのレコードのみが選択され、挿入されることに注意してください。 - 18 行目は、区切り文字を再びデフォルト値の
;にリセットします。 - 19 行目でプロシージャを呼び出します。
同様に、CURSOR を使用して、MySQL のすべてのテーブル行をループできます。 次のセクションを見てみましょう。
ストアド プロシージャで CURSOR を使用して、MySQL テーブルのすべての行をループする
CURSOR を使用して、ストアド プロシージャで結果セットを処理します。 これにより、クエリによって返された一連のレコード (行) をループして、すべての行を個別に処理できます。
CURSOR を使用する際には、次のような CURSOR のプロパティが必要です。
CURSORはセンシティブです。 サーバーが結果テーブルのコピーも作成する必要はありません。CURSORは読み取り専用なので更新できません。CURSORはスクロールできません。 結果セット内のレコード (行) をスキップしたりジャンプしたりせずに、一方向にのみトラバースできます。
コード例:
DROP PROCEDURE IF EXISTS cursor_CALCPERFORMANCE;
DELIMITER ;;
CREATE PROCEDURE cursor_CALCPERFORMANCE()
BEGIN
DECLARE cursor_FIRSTNAME VARCHAR(45) DEFAULT "";
DECLARE cursor_LASTNAME VARCHAR(45) DEFAULT "";
DECLARE done INT DEFAULT FALSE;
DECLARE cursor_e CURSOR FOR SELECT FIRSTNAME,LASTNAME FROM employees;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cursor_e;
read_loop: LOOP
FETCH cursor_e INTO cursor_FIRSTNAME, cursor_LASTNAME;
IF done THEN
LEAVE read_loop;
END IF;
INSERT INTO emp_performance (FIRSTNAME,LASTNAME)
VALUES (cursor_FIRSTNAME, cursor_LASTNAME);
END LOOP;
CLOSE cursor_e;
END;
;;
DELIMITER ;
CALL cursor_CALCPERFORMANCE();
レコードが挿入されたら、SELECT コマンドを使用して emp_performance 出力を確認します。
SELECT * from emp_performance;
出力 (CURSOR を使用した emp_performance テーブル):
PERORM_ID |
FIRSTNAME |
LASTNAME |
PERFORMANCE |
|---|---|---|---|
| 1 | メーヴィッシュ | アシク | ヌル |
| 2 | トーマス | クリストファー | ヌル |
| 3 | ジョン | ダニエル | ヌル |
| 4 | さいら | ジェームズ | ヌル |
行番号を使用したコードの説明
- 行 1 は、同じ名前の既存のプロシージャを削除します。
- 2 行目で区切り文字を
;;に変更します。 - 4 行目は、指定されたプロシージャー名を使用してプロシージャーを作成します。
- 必要なすべてのステートメントは、5 行目と 21 行目の間に記述されます。
- 5 行目で手順を開始します。
- 6、7、および 8 行目は、
VARCHAR(45)、VARCHAR(45)、およびINT型のcursor_FIRSTNAME、cursor_LASTNAME、およびdoneという名前の変数を宣言します。 それぞれ""、""、FALSE。 - 9 行目では、
SELECTステートメントに関連付けられたCURSORを宣言しています。 - 10 行目では、
finished変数を使用してCURSORが結果セットの最後に到達したことを示すNOT FOUNDハンドラを宣言しています。 - 11 行目で
CURSORを開きます。 - 行 12-19 では、
FIRSTNAMEとLASTNAMEのリストを繰り返し処理して、INSERTをemp_performanceテーブルに挿入します。 - 行 20 で
CURSORが終了し、行 21 でストアド プロシージャが終了します。 - 24 行目で区切り文字を再びデフォルトの
;にリセットします。 - 25 行目でプロシージャを呼び出します。
WHILE と CURSOR の使い方の比較
1つのことを達成するために複数の方法がある場合、それぞれのアプローチの長所と短所を知っておく必要があります。
WHILE ループの長所と短所:
| 長所 | 短所 |
|---|---|
CURSOR よりも高速で、最小限のロックを使用します。 |
前後に移動しにくい。 |
tempdb のデータのコピーは作成しません。 |
適切に処理しないと、無限ループに陥る危険性があります。 |
CURSOR の長所と短所:
| 長所 | 短所 |
|---|---|
| カーソルをストアド プロシージャに渡すことができます。 | CTE または WHILE ループを使用する場合と比較して、パフォーマンスが低下します。 |
カーソルは条件を必要とせず、CURSOR で前後に移動できます。 |
コードにグローバル カーソルがあると、エラーが発生する可能性があります。 どうやって? CURSOR は、コード内にネストされたストアド プロシージャによって閉じられる場合があります。 |
