sql >> データベース >  >> RDS >> Mysql

MySQLプリペアドステートメント-ループスルーする方法

    他の人がすでに示唆しているように、私たちは通常避ける 結果セットをループする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スクリプトが得られます。



    1. mysqlデータベースにはいくつのテーブルを作成できますか?

    2. Oracleで一般的なORA-02049とロックの問題をトラブルシューティングする方法

    3. ノードのすべての親を取得するためのSPARQLクエリ

    4. JPA@GeneratedValue列で主キーの値を手動で指定します