0

呼び出しているプロシージャに問題があります。

プロシージャには2つのループがあります。1つは同じネットワーク内の他のデータベースへの接続用で、もう1つは各接続からデータを取得するためのものですが、問題は、最初の接続からデータの最初のパックしか取得しないことです。よくわかりませんが、2番目のループで何か間違ったことをしていて、何かを忘れているのかもしれません。私がそのようなことをするのはこれが2回目であり、それが非常に複雑なのは初めてです。

プロシージャのコードは次のとおりです。

CREATE PROCEDURE `firians`.`sincronizarAgencias` ()
BEGIN
declare nomeAgencia varchar(255);
declare ultimaAgencia int default false;
declare terminouPicagens int default false;

declare agenciasCur cursor for select ip from agencia;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET ultimaAgencia = TRUE;

open agenciasCur;
nomeAgenciasLoop: LOOP

    FETCH agenciasCur INTO nomeAgencia;

    IF ultimaAgencia THEN
        close agenciasCur; 
        LEAVE nomeAgenciasLoop;
    END IF;

    SELECT nomeAgencia;

    DROP VIEW IF EXISTS temp_agencia_view;
    SET @query = CONCAT('CREATE VIEW temp_agencia_view as select data, idempregado, idsociedade, nif, tipo from `', nomeAgencia, '`'); 
    select @query; 
    PREPARE stmt from @query; 
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    blocoPicagens: BEGIN
        declare newData DATETIME;
        declare newIdEmpregado VARCHAR(45);
        declare newIdSociedade bigint(20);
        declare newNif varchar(15);
        declare newTipo varchar(45);

        declare ultimaPicagem int default false;

        -- SELECT data, idempregado, idsociedade, nif, tipo from temp_agencia_view;

        DECLARE picagensCursor cursor for select data, idempregado, idsociedade, nif, tipo from temp_agencia_view;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET ultimaPicagem := TRUE;

        open picagensCursor;
        picagensLoop: LOOP
            fetch picagensCursor into newData, newIdEmpregado, newIdSociedade, newNif, newTipo;

            IF ultimaPicagem THEN
                -- SET ultimaPicagem := false;
                close picagensCursor;
                DROP VIEW IF EXISTS temp_agencia_view; 
                LEAVE picagensLoop;
            END IF;

            INSERT INTO `firians`.`assiduidade`(`data`,`idempregado`,`idsociedade`,`tipo`,`nif`)
            VALUES
            (newData, newIdEmpregado, newIdSociedade, newTipo, newNif);

            INSERT INTO `firians`.`assiduidadebackup`(`data`,`idempregado`,`idsociedade`,`tipo`,`nif`)
            VALUES
            (newData, newIdEmpregado, newIdSociedade, newTipo, newNif);

            set @updateRowQuery = CONCAT('DELETE FROM `', nomeAgencia,'` WHERE idempregado = ', newIdEmpregado, ' AND idsociedade = ', newIdSociedade, ' AND tipo = ', newTipo, ' AND data LIKE \'', newData, "'"); 
            select @updateRowQuery;
            PREPARE stmtUpdate from @updateRowQuery; 
            EXECUTE stmtUpdate; 
            DEALLOCATE PREPARE stmtUpdate;

        END LOOP picagensLoop;

    DROP VIEW IF EXISTS temp_agencia_view;
        -- select * from temp_agencia_view;           
    END blocoPicagens;

END LOOP nomeAgenciasLoop;

DROP VIEW IF EXISTS temp_agencia_view;
END

手伝って頂けますか?

よろしく、

エルカス

4

1 に答える 1

1

あなたの問題は、MySQLが準備済みステートメント内からサポートしていないことだと思います。 CREATE VIEW代わりに一時テーブルを使用できます。

SET @query = CONCAT('
  CREATE TEMPORARY TABLE temp_agencia_tbl
    select data, idempregado, idsociedade, nif, tipo from `', nomeAgencia, '`
');

INSERT ... SELECTただし、 2 番目のカーソルを完全に回避するために、準備されたステートメント内から構文を使用できるため、このアプローチはやり過ぎのように思えます。

SET @q1 = CONCAT('
  INSERT INTO firians.assiduidade
          (data, idempregado, idsociedade, tipo, nif)
    SELECT data, idempragado, idsociedade, tipo, nif FROM `', nomeAgencia, '`
');
SET @q2 = CONCAT('
  INSERT INTO firians.assiduidadebackup
          (data, idempregado, idsociedade, tipo, nif)
    SELECT data, idempragado, idsociedade, tipo, nif FROM `', nomeAgencia, '`
');
SET @q3 = CONCAT('TRUNCATE `', nomeAgencia, '`');

しかし、これでもやり過ぎのように思えます 。テーブルを結合するために使用GROUP_CONCATする単一のINSERT ... SELECTステートメントを使用して作成することにより、最初のカーソルを省略することもできるからです。UNION

SELECT
  CONCAT('
    INSERT INTO firians.assiduidade
            (data, idempregado, idsociedade, tipo, nif)'
  , GROUP_CONCAT('
      SELECT data, idempregado, idsociedade, tipo, nif FROM `', ip, '`'
      SEPARATOR ' UNION ALL ')
  ) INTO @q1
, CONCAT('
    INSERT INTO firians.assiduidadebackup
            (data, idempregado, idsociedade, tipo, nif)'
  , GROUP_CONCAT('
      SELECT data, idempregado, idsociedade, tipo, nif FROM `', ip, '`'
      SEPARATOR ' UNION ALL ')
  ) INTO @q2
, CONCAT('
    DELETE FROM ', GROUP_CONCAT('`', ip, '`'), '
          USING ', GROUP_CONCAT('`', ip, '`')
  ) INTO @q3
FROM agencia;

しかし、そうは言っても、このように変数テーブルを使用することは、一般に、データベース設計が不十分であることを示しています。同様のスキーマを持つ複数のテーブルの代わりに、すべての異なるレコードを組み合わせた単一のテーブル (データがどのテーブルから発生したかなどの違いを示す追加の列を含む) の方がはるかに簡単であることがわかるでしょう。たとえば、上記は単純に次のように縮小されます。

INSERT INTO firians.assiduidade
        (data, idempregado, idsociedade, tipo, nif)
  SELECT data, idempregado, idsociedade, tipo, nif FROM CombinedTable;

INSERT INTO firians.assiduidadebackup
        (data, idempregado, idsociedade, tipo, nif)
  SELECT data, idempregado, idsociedade, tipo, nif FROM CombinedTable;

TRUNCATE CombinedTable;

元の SP では対処されていなかったため、この回答では同時実行の問題に対処していないことに注意してください。明らかに、並行性が問題になる可能性がある場合は、これらのアクションをトランザクション内に含めるなどのロック戦略を検討する必要があります。

また、これまで行ってきたようにSQL識別子を準備済みステートメントに連結する必要がありますが、実行時に値を準備済みステートメントに渡すことができることも指摘する価値があります(たとえば、DELETEステートメントに。実際、そのステートメントは1回につき1回しか準備できませんでした)。最初のカーソルの反復と、2 番目のカーソルの反復ごとに異なる値で実行されます)。

于 2012-05-25T20:35:58.593 に答える