Jak sugerowali już inni, zazwyczaj unikamy przechodzenie przez zestaw wyników RBAR (wiersz po rzędzie agonizing) głównie ze względu na wydajność. Po prostu nie chcemy wyrobić w sobie nawyku przeglądania zestawu wyników w pętli. Ale to nie odpowiada na zadane pytanie.
Aby odpowiedzieć na zadane pytanie, oto prosty przykład programu przechowywanego w MySQL, który używa kursora CURSOR do indywidualnego przetwarzania wierszy zwróconych przez zapytanie. MySQL nie obsługuje anonimowych bloków, więc jedynym sposobem, aby to zrobić, jest program przechowywany w MySQL, taki jak 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 ;
Aby wykonać procedurę:
CALL loop_through_var_list();
UWAGI:Składnia przetwarzania kursora w MySQL jest nieco inna niż w innych bazach danych.
Aby uzyskać "pętlę", musimy użyć LOOP ... END LOOP
konstrukcja.
Ale aby zapobiec nieskończonej pracy tej pętli, potrzebujemy instrukcji LEAVE, która pozwoli nam wyjść z pętli.
Używamy testu warunkowego, aby określić, kiedy wyjść. W tym przykładzie chcemy wyjść po zakończeniu przetwarzania ostatniego wiersza.
FETCH
wyrzuci wyjątek, gdy nie będzie więcej wierszy do pobrania.
„Łapiemy” ten wyjątek w KONTYNUOWANIU OBSŁUGI (z jakiegoś tajemniczego powodu „obsługi” muszą zadeklarować ostatnią rzecz; MySQL zgłasza błąd, jeśli próbujemy zadeklarować coś po OPROGRAMOWANIU (innym niż inny OBSŁUGA).
Kiedy MySQL zgłasza wyjątek „no more rows”, uruchamia kod obsługi. W tym przykładzie po prostu ustawiamy zmienną (o nazwie done
) na wartość.
Ponieważ jest to procedura obsługi „kontynuuj”, przetwarzanie rozpoczyna się od początku w instrukcji, w której zgłoszono wyjątek, w tym przypadku będzie to instrukcja następująca po FETCH. Tak więc pierwszą rzeczą, którą robimy, jest sprawdzenie, czy „skończyliśmy”, czy nie. Jeśli skończyliśmy, to wychodzimy z pętli i zamykamy kursor.
W przeciwnym razie wiemy, że mamy id
wartość z var_list
przechowywane w zmiennej procedury o nazwie v_id
. Więc teraz możemy robić, co chcemy. Wygląda na to, że chcesz umieścić tekst SQL w zmiennej zdefiniowanej przez użytkownika (w tym w wartości v_id w tekście SQL, a następnie PREPARE, EXECUTE i DEALLOCATE PREPARE).
Pamiętaj, aby zadeklarować v_id
zmienna z odpowiednim typem danych, który pasuje do typu danych id
kolumna w var_list
, właśnie założyłem, że jest to INT.
Kiedy dochodzimy do końca pętli, MySQL "zapętla się" z powrotem do początku pętli i zaczynamy od nowa.
W treści pętli prawdopodobnie będziesz chciał wpisać CONCAT v_id do tekstu SQL, który chcesz wykonać. Wygląda na to, że masz już uchwyt na przygotowanie, cofnięcie przydziału. Do testowania możesz dodać klauzulę LIMIT do SELECT w deklaracji kursora, a następnie wykonać prosty SELECT v_id; w ciele, aby sprawdzić, czy pętla działa, zanim dodasz więcej kodu.
KONTYNUACJA
Chciałem wspomnieć o innym alternatywnym podejściu do zadania, tj. uruchamianiu serii instrukcji opartych na szablonie, zastępując wartościami dostarczonymi z pojedynczej instrukcji SQL select...
Na przykład, gdybym miał ten szablon:
SELECT *
INTO OUTFILE '/tmp/[email protected]'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM data
WHERE id = @ID
ORDER BY 1
i musiałem zastąpić wystąpienia @ID konkretną wartością id z listy zwracanej z instrukcji SELECT, np.
SELECT id
FROM var_list
WHERE id IS NOT NULL
GROUP BY id
Prawdopodobnie nie użyłbym programu przechowywanego w MySQL z pętlą CURSOR, zastosowałbym inne podejście.
Wykorzystałbym instrukcję SELECT do wygenerowania zestawu instrukcji SQL, które mogłyby zostać wykonane. Zakładając id
jest typem całkowitym, prawdopodobnie zrobiłbym coś takiego:
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
Dla każdej wartości id
zwrócone z s
, instrukcja zwraca tekst instrukcji SQL SELECT, którą można (i trzeba) wykonać. Przechwycenie tego do pliku tekstowego dałoby mi skrypt SQL, który mógłbym uruchomić.