他の人がすでに示唆しているように、私たちは通常避ける 結果セットをループするRBAR (行を苦しめることによる行)主にパフォーマンス上の理由から。結果セットをループする習慣をつけたくないだけです。しかし、それはあなたが尋ねた質問に答えません。
あなたが尋ねた質問に答えるために、これは、CURSORを使用してクエリによって返された行を個別に処理するMySQLストアドプログラムの基本的な例です。 MySQLは匿名ブロックをサポートしていないため、これを行う唯一の方法は、PROCEDURE
などのMySQLストアドプログラムを使用することです。DELIMITER $$
CREATE PROCEDURE loop_through_var_list
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_id INT DEFAULT NULL;
DECLARE csr_var_list CURSOR FOR SELECT id FROM var_list ORDER BY id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN csr_var_list;
get_id: LOOP
FETCH csr_var_list INTO v_id;
IF done = 1 THEN
LEAVE get_id;
END IF;
-- at this point, we have an id value in v_id, so we can do whatever
SET @s1 = CONCAT('SELECT ... WHERE id =''', v_id, ''' ...');
END LOOP get_id;
CLOSE csr_var_list;
END$$
DELIMITER ;
手順を実行するには:
CALL loop_through_var_list();
注:MySQLでCURSORを処理するための構文は、他のデータベースとはかなり異なります。
「ループ」を取得するには、LOOP ... END LOOP
を使用する必要があります 構築します。
ただし、そのループが永久に実行されないようにするには、ループを終了できるLEAVEステートメントが必要です。
条件付きテストを使用して、いつ出発するかを決定します。この例では、最後の行の処理が終了した後で終了します。
FETCH
フェッチする行がなくなると、例外がスローされます。
CONTINUE HANDLERでその例外を「キャッチ」します(なんらかの理由で、「ハンドラー」は最後に宣言する必要があります。HANDLER(別のHANDLER以外)の後に何かを宣言しようとすると、MySQLはエラーをスローします。
>
MySQLが「行がありません」という例外をスローすると、ハンドラコードが起動します。この例では、変数(done
という名前)を設定しているだけです。 )値に。
これは「続行」ハンドラーであるため、例外がスローされたステートメント(この場合は、FETCHに続くステートメント)から処理が再開されます。したがって、最初に行うことは、「完了」したかどうかを確認することです。 「完了」したら、ループを終了してカーソルを閉じます。
それ以外の場合は、id
があることがわかります var_list
からの値 v_id
という名前のプロシージャ変数に格納されます 。これで、やりたいことが何でもできるようになりました。 SQLテキストをユーザー定義変数に入れたいようです(v_idの値をSQLテキストに入れてから、PREPARE、EXECUTE、およびDEALLOCATEPREPAREを含めます。
必ずv_id
を宣言してください id
のデータ型と一致する適切なデータ型の変数 var_list
の列 、INTだと思っただけです。
ループの最後に到達すると、MySQLはループの最初に「ループ」して戻り、オフになります。
ループの本体では、実行するSQLテキストにv_idをCONCATする必要があります。すでにPREPARE、DEALLOCATE準備のハンドルを持っているようです。テストのために、カーソル宣言のSELECTにLIMIT句を追加してから、単純なSELECTv_idを実行することをお勧めします。本文では、コードを追加する前に、ループが機能していることを確認するだけです。
フォローアップ
タスクに対する別の代替アプローチについて言及したいと思います。つまり、テンプレートに基づいて一連のステートメントを実行し、単一のSQLselectステートメントから提供された値に置き換えます...
たとえば、このテンプレートがある場合:
SELECT *
INTO OUTFILE '/tmp/[email protected]'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM data
WHERE id = @ID
ORDER BY 1
@IDの出現を、SELECTステートメントから返されたリストの特定のID値に置き換える必要がありました。
SELECT id
FROM var_list
WHERE id IS NOT NULL
GROUP BY id
おそらく、CURSORループでMySQLストアドプログラムを使用することはないでしょう。別のアプローチを使用します。
SELECTステートメントを使用して、実行可能なSQLステートメントのセットを生成します。 id
を想定 は整数型なので、次のようなことをする可能性があります:
SELECT CONCAT(' SELECT *
INTO OUTFILE ''/tmp/orders_',s.id,'.csv''
FIELDS TERMINATED BY '','' ENCLOSED BY ''"''
LINES TERMINATED BY ''\n''
FROM data
WHERE id = ',s.id,'
ORDER BY 1;') AS `stmt`
FROM ( SELECT v.id
FROM var_list v
WHERE v.id IS NOT NULL
GROUP BY v.id
) s
ORDER BY s.id
id
のすべての値に対して s
から返される 、ステートメントは、実行できる(および実行する必要がある)SQLSELECTステートメントのテキストを返します。これをテキストファイルに取り込むと、実行できるSQLスクリプトが得られます。