Jak již naznačili ostatní, obvykle se vyhýbáme procházením sady výsledků RBAR (řádek po agonizujícím řádku) především z důvodu výkonu. Jen si nechceme zvyknout procházet sadu výsledků. Ale to není odpověď na otázku, kterou jste položili.
Abychom odpověděli na otázku, kterou jste položili, zde je základní příklad programu uloženého v MySQL, který používá CURSOR k individuálnímu zpracování řádků vrácených dotazem. MySQL nepodporuje anonymní bloky, takže jediný způsob, jak to udělat, je v programu uloženém v MySQL, jako je 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 ;
Postup provedení:
CALL loop_through_var_list();
POZNÁMKY:Syntaxe pro zpracování CURSORu v MySQL je docela odlišná od jiných databází.
Abychom získali "smyčku", musíme použít LOOP ... END LOOP
konstrukce.
Aby však tato smyčka neběžela navždy, potřebujeme příkaz LEAVE, který nám umožní smyčku opustit.
K určení, kdy odejít, používáme podmíněný test. V tomto příkladu chceme skončit poté, co dokončíme zpracování posledního řádku.
FETCH
se chystá vyvolat výjimku, když již nejsou k načtení žádné další řádky.
Tuto výjimku „zachytíme“ v POKRAČOVACÍM HANDLER (z nějakého tajemného důvodu musí „obslužné rutiny“ do posledního deklarovaného obsahu; MySQL vyvolá chybu, pokud se pokusíme deklarovat něco za HANDLER (jiný než jiný HANDLER.)
Když MySQL vyvolá výjimku „žádné další řádky“, spustí se kód handleru. V tomto příkladu pouze nastavujeme proměnnou (s názvem done
) na hodnotu.
Vzhledem k tomu, že se jedná o obslužnou rutinu „pokračování“, zpracování začne zpět od příkazu, kde byla vyvolána výjimka, v tomto případě to bude příkaz následující po FETCH. Takže první věc, kterou uděláme, je zkontrolovat, zda jsme "hotoví" nebo ne. Pokud jsme "hotoví", opustíme smyčku a zavřeme kurzor.
Jinak víme, že máme id
hodnota z var_list
uloženy v proměnné procedury s názvem v_id
. Takže teď si můžeme dělat, co chceme. Vypadá to, že chcete vložit nějaký text SQL do uživatelem definované proměnné (včetně hodnoty v_id do textu SQL, pak PREPARE, EXECUTE a DEALLOCATE PREPARE.
Nezapomeňte deklarovat v_id
proměnná s příslušným datovým typem, který odpovídá datovému typu id
v var_list
, právě jsem předpokládal, že je to INT.
Když se dostaneme na konec smyčky, MySQL se "zacyklí" zpět na začátek smyčky a jedeme znovu.
V těle smyčky budete pravděpodobně chtít CONCAT v_id do textu SQL, který chcete spustit. Vypadá to, že už máte připravenou přípravu PŘIPRAVIT, ROZDĚLIT. Pro testování můžete chtít přidat klauzuli LIMIT na SELECT v deklaraci kurzoru a poté provést jednoduchý SELECT v_id; v těle jen pro ověření funkčnosti smyčky, než přidáte další kód.
NÁSLEDOVAT
Chtěl jsem zmínit další alternativní přístup k úkolu, tj. spuštění řady příkazů na základě šablony, nahrazování hodnot poskytnutých jedním příkazem SQL select...
Pokud bych měl například tuto šablonu:
SELECT *
INTO OUTFILE '/tmp/[email protected]'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM data
WHERE id = @ID
ORDER BY 1
a potřeboval jsem nahradit výskyty @ID konkrétní hodnotou id ze seznamu vráceného z příkazu SELECT, např.
SELECT id
FROM var_list
WHERE id IS NOT NULL
GROUP BY id
Pravděpodobně bych nepoužil program uložený v MySQL se smyčkou CURSOR, použil bych jiný přístup.
Použil bych příkaz SELECT ke generování sady příkazů SQL, které by mohly být provedeny. Za předpokladu id
je celočíselný typ, pravděpodobně bych udělal něco takového:
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
Pro každou hodnotu id
vráceno z s
, příkaz vrací text příkazu SQL SELECT, který se může (a musí) provést. Když to zachytím do textového souboru, získám skript SQL, který bych mohl spustit.