Mysql
 sql >> Database >  >> RDS >> Mysql

Dichiarazione preparata da MySQL - Come eseguire il ciclo

Come altri hanno già suggerito, in genere evitiamo scorrendo un insieme di risultati RBAR (riga per riga agonizzante) principalmente per motivi di prestazioni. Semplicemente non vogliamo prendere l'abitudine di scorrere un set di risultati. Ma questo non risponde alla domanda che hai posto.

Per rispondere alla domanda che hai posto, ecco un esempio rudimentale di un programma memorizzato MySQL che utilizza un CURSOR per elaborare individualmente le righe restituite da una query. MySQL non supporta i blocchi anonimi, quindi l'unico modo per farlo è in un programma memorizzato in MySQL, come una PROCEDURA

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 ;

Per eseguire la procedura:

CALL loop_through_var_list();

NOTE:La sintassi per l'elaborazione di un CURSOR in MySQL è leggermente diversa da quella di altri database.

Per ottenere il "looping", dobbiamo usare un LOOP ... END LOOP costruire.

Ma per impedire che quel ciclo funzioni per sempre, abbiamo bisogno di un'istruzione LEAVE che ci consenta di uscire dal ciclo.

Usiamo un test condizionale per determinare quando partire. In questo esempio, vogliamo uscire dopo aver terminato l'elaborazione dell'ultima riga.

Il FETCH genererà un'eccezione quando non ci sono più righe da recuperare.

Noi "catturamo" quell'eccezione in un CONTINUE HANDLER (per qualche ragione arcana, i "handler" devono dichiarare le ultime cose; MySQL genera un errore se proviamo a dichiarare qualcosa dopo un HANDLER (diverso da un altro HANDLER.)

Quando MySQL genera l'eccezione "niente più righe", viene attivato il codice del gestore. In questo esempio, stiamo semplicemente impostando una variabile (denominata done ) a un valore.

Poiché si tratta di un gestore "continua", l'elaborazione viene avviata di nuovo dall'istruzione in cui è stata generata l'eccezione, in questo caso sarà l'istruzione successiva al FETCH. Quindi, la prima cosa che facciamo è controllare se abbiamo "finito" o meno. Se abbiamo "fatto", usciamo dal ciclo e chiudiamo il cursore.

In caso contrario, sappiamo di avere un id valore da var_list memorizzato in una variabile di procedura denominata v_id . Quindi ora possiamo fare quello che vogliamo. Sembra che tu voglia inserire del testo SQL in una variabile definita dall'utente (incluso il valore di v_id nel testo SQL, quindi PREPARE, EXECUTE e DEALLOCATE PREPARE.

Assicurati di dichiarare il v_id variabile con il tipo di dati appropriato, che corrisponde al tipo di dati dell'id colonna in var_list , ho appena dato per scontato che sia un INT.

Quando raggiungiamo la fine del ciclo, MySQL torna all'inizio del ciclo e si riparte.

Nel corpo del ciclo, probabilmente vorrai CONCAT v_id nel testo SQL che desideri eseguire. Sembra che tu abbia già un handle sulla preparazione PREPARE, DEALLOCATE. Per il test, potresti voler aggiungere una clausola LIMIT su SELECT nella dichiarazione del cursore, quindi eseguire un semplice SELECT v_id; nel corpo, solo per verificare che il ciclo funzioni, prima di aggiungere altro codice.

SEGUITO

Volevo citare un altro approccio alternativo all'attività, ovvero eseguire una serie di istruzioni basate su un modello, sostituendo i valori forniti da una singola istruzione SQL select...

Ad esempio, se avessi questo modello:

SELECT * 
  INTO OUTFILE '/tmp/[email protected]'
  FIELDS TERMINATED BY ',' ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
FROM data 
WHERE id = @ID
ORDER BY 1 

e dovevo sostituire le occorrenze di @ID con un valore id specifico da un elenco restituito da un'istruzione SELECT, ad es.

SELECT id
  FROM var_list
 WHERE id IS NOT NULL
 GROUP BY id

Probabilmente non userei un programma memorizzato in MySQL con un ciclo CURSOR, userei un approccio diverso.

Userei un'istruzione SELECT per generare una serie di istruzioni SQL che potrebbero essere eseguite. Assumendo id è di tipo intero, probabilmente farei qualcosa del genere:

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

Per ogni valore di id restituito da s , l'istruzione restituisce il testo di un'istruzione SQL SELECT che potrebbe (e deve) essere eseguita. Catturarlo in un file di testo mi darebbe uno script SQL che potrei eseguire.