Som andra redan har föreslagit, undviker vi vanligtvis loopar genom en resultatuppsättning RBAR (rad för plågsam rad) främst av prestationsskäl. Vi vill bara inte ta för vana att gå igenom en resultatuppsättning. Men det svarar inte på frågan du ställde.
För att svara på frågan du ställde, här är ett rudimentärt exempel på ett MySQL-lagrat program som använder en CURSOR för att individuellt bearbeta rader som returneras av en fråga. MySQL stöder inte anonyma blockeringar, så det enda sättet att göra detta är i ett MySQL-lagrat program, som en PROCEDUR
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 ;
För att utföra proceduren:
CALL loop_through_var_list();
ANMÄRKNINGAR:Syntaxen för att bearbeta en CURSOR i MySQL skiljer sig ganska mycket från andra databaser.
För att få "looping" måste vi använda en LOOP ... END LOOP
konstruera.
Men för att förhindra att den slingan körs för alltid behöver vi en LEAVE-sats som gör att vi kan lämna slingan.
Vi använder ett villkorligt test för att avgöra när vi ska lämna. I det här exemplet vill vi avsluta efter att vi har bearbetat den sista raden.
FETCH
kommer att göra ett undantag när det inte finns fler rader att hämta.
Vi "fångar" det undantaget i en CONTINUE HANDLER (av någon svår anledning måste "hanterarna" till de sista sakerna deklareras; MySQL ger ett felmeddelande om vi försöker deklarera något efter en HANDLER (annat än en annan HANDLER.)
När MySQL kastar undantaget "inga fler rader" avfyras hanterarkoden. I det här exemplet ställer vi bara in en variabel (som heter done
) till ett värde.
Eftersom det är en "fortsätt"-hanterare, startar bearbetningen tillbaka vid den sats där undantaget kastades, i det här fallet kommer det att vara satsen efter FETCH. Så det första vi gör är att kontrollera om vi är "klara" eller inte. Om vi är "klara", lämnar vi slingan och stänger markören.
Annars vet vi att vi har ett id
värde från var_list
lagras i en procedurvariabel med namnet v_id
. Så nu kan vi göra vad vi vill. Det verkar som att du vill lägga in lite SQL-text i en användardefinierad variabel (inklusive värdet på v_id i SQL-texten, sedan FÖRBEREDA, UTFÖRA och AVALLOKERA FÖRBEREDA.
Se till att deklarera v_id
variabel med lämplig datatyp, som matchar datatypen för id
kolumn i var_list
, jag har precis antagit att det är en INT.
När vi når slutet av loopen "loopar" MySQL tillbaka till början av loopen, och iväg igen.
I slingans brödtext kommer du troligen att vilja CONCAT v_id i SQL-texten du vill köra. Det verkar som att du redan har koll på förberedelserna för att förbereda, avfördela. För testning kanske du vill lägga till en LIMIT-sats på SELECT i markördeklarationen och sedan göra en enkel SELECT v_id; i kroppen, bara för att verifiera att slingan fungerar, innan du lägger till mer kod.
UPPFÖLJNING
Jag ville nämna ett annat alternativt tillvägagångssätt för uppgiften, d.v.s. att köra en serie satser baserade på en mall och ersätta värden från en enda SQL select-sats...
Om jag till exempel hade den här mallen:
SELECT *
INTO OUTFILE '/tmp/[email protected]'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM data
WHERE id = @ID
ORDER BY 1
och jag behövde ersätta förekomsterna av @ID med ett specifikt id-värde från en lista som returnerades från en SELECT-sats, t.ex.
SELECT id
FROM var_list
WHERE id IS NOT NULL
GROUP BY id
Jag skulle förmodligen inte använda ett MySQL-lagrat program med en CURSOR-loop, jag skulle använda ett annat tillvägagångssätt.
Jag skulle använda en SELECT-sats för att generera en uppsättning SQL-satser som kan köras. Förutsatt id
är heltalstyp, skulle jag förmodligen göra något så här:
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
För varje värde på id
returneras från s
, returnerar satsen texten i en SQL SELECT-sats som kan (och behöver) köras. Att fånga det i en textfil skulle ge mig ett SQL-skript som jag skulle kunna köra.