Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Przygotowana instrukcja MySQL — jak przejść przez pętlę

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ć.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wymagany do przyłączenia się do 2 stołów z ich FK w trzecim stole

  2. Obliczanie całkowitej ilości sprzętu dla zakresu dat

  3. Zmiana silnika tabel w MySQL

  4. Jak dodać serię ciągów w inkrementacji id w dowolnej tabeli?

  5. Jak wygenerować widok drzewa z tego zestawu wyników na podstawie algorytmu przechodzenia przez drzewo?