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

MySQL Prepared Statement - Sådan går du igennem

Som andre allerede har foreslået, undgår vi typisk sløjfe gennem et resultatsæt RBAR (række for pinefulde række) primært af præstationsmæssige årsager. Vi ønsker bare ikke at vænne os til at gennemgå et resultatsæt. Men det besvarer ikke det spørgsmål, du stillede.

For at besvare det spørgsmål, du stillede, er her et rudimentært eksempel på et MySQL-lagret program, der bruger en CURSOR til individuelt at behandle rækker, der returneres af en forespørgsel. MySQL understøtter ikke anonyme blokeringer, så den eneste måde at gøre dette på er i et MySQL-lagret program, f.eks. en PROCEDURE

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 ;

Sådan udføres proceduren:

CALL loop_through_var_list();

BEMÆRKNINGER:Syntaksen til at behandle en CURSOR i MySQL er en del anderledes end andre databaser.

For at få "looping" skal vi bruge en LOOP ... END LOOP konstruere.

Men for at forhindre den løkke i at køre for evigt, har vi brug for en LEAVE-sætning, der giver os mulighed for at forlade løkken.

Vi bruger en betinget test til at bestemme, hvornår vi skal rejse. I dette eksempel ønsker vi at afslutte, når vi er færdige med at behandle den sidste række.

FETCH kommer til at kaste en undtagelse, når der ikke er flere rækker, der skal hentes.

Vi "fanger" den undtagelse i en CONTINUE HANDLER (af en eller anden mystisk årsag skal "handlerne" til de sidste ting erklæret; MySQL kaster en fejl, hvis vi forsøger at erklære noget efter en HANDLER (andre end en anden HANDLER.)

Når MySQL kaster undtagelsen "ikke flere rækker", udløser det handlerkoden. I dette eksempel indstiller vi blot en variabel (ved navn done ) til en værdi.

Da det er en "fortsæt"-handler, starter behandlingen igen ved sætningen, hvor undtagelsen blev kastet, i dette tilfælde vil det være sætningen efter FETCH. Så den første ting vi gør er at tjekke om vi er "færdige" eller ej. Hvis vi er "færdige", så forlader vi løkken og lukker markøren.

Ellers ved vi, at vi har et id værdi fra var_list gemt i en procedurevariabel ved navn v_id . Så nu kan vi gøre, hvad vi vil. Det ser ud til, at du vil indsætte noget SQL-tekst i en brugerdefineret variabel (inklusive værdien af ​​v_id i SQL-teksten, derefter PREPARE, EXECUTE og DEALLOCATE PREPARE.

Sørg for at angive v_id variabel med den relevante datatype, der matcher datatypen for id kolonne i var_list , jeg har lige antaget, at det er en INT.

Når vi når slutningen af ​​løkken, "løkker" MySQL tilbage til begyndelsen af ​​løkken, og så går vi igen.

I løkkens brødtekst vil du sandsynligvis CONCAT v_id ind i den SQL-tekst, du vil udføre. Det ser ud til, at du allerede har styr på forberedelsen, AFDELING. Til test kan du tilføje en LIMIT-sætning på SELECT i markørerklæringen og derefter lave en simpel SELECT v_id; i kroppen, bare for at bekræfte, at løkken fungerer, før du tilføjer mere kode.

OPFØLGNING

Jeg ønskede at nævne en anden alternativ tilgang til opgaven, dvs. at køre en række sætninger baseret på en skabelon, der erstatter værdier fra en enkelt SQL select-sætning...

For eksempel, hvis jeg havde denne skabelon:

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

og jeg havde brug for at erstatte forekomsterne af @ID med en specifik id-værdi fra en liste returneret fra en SELECT-sætning, f.eks.

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

Jeg ville sandsynligvis ikke bruge et MySQL-lagret program med en CURSOR-løkke, jeg ville bruge en anden tilgang.

Jeg ville gøre brug af en SELECT-sætning til at generere et sæt SQL-sætninger, som kunne udføres. Forudsat id er heltalstype, ville jeg sandsynligvis gøre noget som dette:

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

For hver værdi af id returneret fra s , returnerer sætningen teksten af ​​en SQL SELECT-sætning, der kunne (og skal) udføres. At fange det i en tekstfil ville give mig et SQL-script, jeg kunne køre.



  1. mysqldump med --hvor klausulen ikke virker

  2. Laravel-tidsstempel bliver opdateret uden eksplicit opfordring til at gøre det

  3. parsing af brugerskrevne fuldtekstsøgningsforespørgsler ind i WHERE-klausulen i MySQL ved hjælp af PHP

  4. mysql Ugyldigt kolonneantal i CSV-input under import af csv-fil