Както други вече предложиха, обикновено избягваме преминаване през набор от резултати RBAR (ред по агонизиращ ред) предимно от съображения за ефективност. Просто не искаме да придобием навика да преглеждаме набор от резултати. Но това не отговаря на въпроса, който зададете.
За да отговорите на въпроса, който сте задали, ето елементарен пример за съхранена в MySQL програма, която използва CURSOR за индивидуална обработка на редове, върнати от заявка. MySQL не поддържа анонимни блокове, така че единственият начин да направите това е в съхранена в MySQL програма, като ПРОЦЕДУРА
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 ;
За да изпълните процедурата:
CALL loop_through_var_list();
ЗАБЕЛЕЖКИ:Синтаксисът за обработка на CURSOR в MySQL е доста различен от другите бази данни.
За да получим "зацикляне", трябва да използваме LOOP ... END LOOP
конструкция.
Но за да предотвратим този цикъл да работи завинаги, се нуждаем от оператор LEAVE, който ще ни позволи да излезем от цикъла.
Използваме условен тест, за да определим кога да напуснем. В този пример искаме да излезем, след като приключим с обработката на последния ред.
FETCH
ще хвърли изключение, когато няма повече редове за извличане.
Ние „улавяме“ това изключение в CONTINUE HANDLER (по някаква тайна причина „обработчиците“ трябва да декларират последните неща; MySQL хвърля грешка, ако се опитаме да декларираме нещо след HANDLER (различен от друг HANDLER).)
Когато MySQL хвърли изключението "няма повече редове", това задейства кода на манипулатора. В този пример ние просто задаваме променлива (с име done
). ) до стойност.
Тъй като това е манипулатор за "продължаване", обработката започва обратно от оператора, където е изхвърлено изключението, в този случай това ще бъде операторът след FETCH. И така, първото нещо, което правим, е да проверим дали сме „свършени“ или не. Ако сме "готови", тогава излизаме от цикъла и затваряме курсора.
В противен случай знаем, че имаме id
стойност от var_list
се съхранява в променлива на процедурата с име v_id
. Така че сега можем да правим каквото си искаме. Изглежда, че искате да поставите малко SQL текст в дефинирана от потребителя променлива (включително в стойността на v_id в SQL текста, след това ПОДГОТОВЯТЕ, ИЗПЪЛНЯВАТЕ и ОТМЕНЯТЕ ПОДГОТОВКА.
Не забравяйте да декларирате v_id
променлива с подходящия тип данни, който съвпада с типа данни на id
колона в var_list
, току-що предположих, че е INT.
Когато стигнем до края на цикъла, MySQL се „връща“ в началото на цикъла и тръгваме отново.
В тялото на цикъла, вероятно ще искате да СВЪРНЕТЕ v_id в SQL текста, който искате да изпълните. Изглежда, че вече имате контрол върху подготовката PREPARE, DEALLOCATE. За тестване може да искате да добавите клауза LIMIT към SELECT в декларацията на курсора и след това да направите прост SELECT v_id; в тялото, само за да се уверите, че цикълът работи, преди да добавите още код.
ПОСЛЕДВАНЕ
Исках да спомена друг алтернативен подход към задачата, т.е. изпълняване на поредица от изрази, базирани на шаблон, заместващи стойности, предоставени от един оператор за избор на SQL...
Например, ако имах този шаблон:
SELECT *
INTO OUTFILE '/tmp/[email protected]'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM data
WHERE id = @ID
ORDER BY 1
и трябваше да заменя появата на @ID с конкретна стойност на идентификатор от списък, върнат от оператор SELECT, напр.
SELECT id
FROM var_list
WHERE id IS NOT NULL
GROUP BY id
Вероятно не бих използвал MySQL съхранена програма с цикъл CURSOR, бих използвал различен подход.
Бих използвал оператор SELECT, за да генерирам набор от SQL оператори, които могат да бъдат изпълнени. Ако приемем id
е целочислен тип, вероятно бих направил нещо подобно:
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
За всяка стойност на id
върнати от s
, операторът връща текста на SQL оператор SELECT, който може (и трябва да се) изпълни. Записването на това в текстов файл ще ми даде SQL скрипт, който мога да стартирам.