Cviceni 7
-- KURSORY
Kurzory pouzivame pro zpracovani vysledku prikazu SELECT
(typicky po jednotlivych radcich).

1) Deklarace kurzoru:
Nejprve je nutne kursor deklarovat v casti declare. 
Tim se vsak prikaz SELECT jeste nevykonava.

Syntaxe deklarace kursoru:
 CURSOR cursor_name [(parameter[, parameter]...)] IS select_statement;

Parametr vypada:
 cursor_parameter_name [IN] datatype [DEFAULT expression]

Priklad:
SQL> DECLARE
SQL>   CURSOR pr1 IS SELECT jmeno,mzda FROM zamestnanci WHERE id = 1;
SQL>   CURSOR pr2(jm VARCHAR2) IS SELECT * FROM zamestnanci WHERE jmeno LIKE jm;
SQL> BEGIN ...


2) Otevreni a uzavreni kursoru
...
BEGIN
  OPEN pr1;
  OPEN pr2('Pep%');
  ...
  CLOSE pr1;
  CLOSE pr2;
END;


3) Ziskani dat

a) Prikaz FETCH
 
FETCH jmeno_kursoru INTO promenna,... ;

Priklad:  
DECLARE
  CURSOR pr1 IS SELECT * FROM zamestnanci;
  my_rec zamestnanci%ROWTYPE;
BEGIN
  OPEN pr1;
  LOOP
    FETCH pr1 INTO my_rec;
    EXIT WHEN pr1%NOTFOUND;
    -- zpracovani dat ...
  END LOOP;
  CLOSE pr1;
END;

b) Kursorovy FOR cyklus
DECLARE
  CURSOR pr1 IS SELECT * FROM zamestnanci;
BEGIN
  FOR emp_rec IN pr1 LOOP
    ...
  END LOOP;
END;


-- Nebo primo bez deklarace kurzoru:
BEGIN
  FOR emp_rec IN (SELECT * FROM zamestnanci) LOOP
    ...
  END LOOP;
END;


c) Prikaz BULK COLLECT:
Prikaz FETCH ziska vzdy jen jeden radek vysledku. Pro ziskani vsech radku
vysledku muzeme vyuzit prikaz BULK COLLECT (vyzaduje promennou 
typu tabulka - presneji kolekce).
 
DECLARE
  TYPE NameTab IS TABLE OF zamestnanci.jmeno%TYPE;
  names NameTab;
  CURSOR pr1 IS SELECT jmeno FROM zamestnanci WHERE mzda > 5000;
BEGIN
  OPEN pr1;
  FETCH pr1 BULK COLLECT INTO names;
  CLOSE pr1;
  --  zpracuj names ...
  FOR i IN names.first .. names.last LOOP
    DBMS_OUTPUT.PUT_LINE('Zamestnanec ' || names(i));
  END LOOP;
END;

-- Nekdy je nejdrive nutne povolit tento vystup pomoci prikazu sqlplus: SQL> SET SERVEROUTPUT ON


4) Atributy %FOUND, %ISOPEN, %NOTFOUND, %ROWCOUNT nad kurzory
%FOUND - posledni FETCH vratil nejaka data
%NOTFOUND - posledni FETCH jiz nevratil zadna data
%ISOPEN - kursor je otevren
%ROWCOUNT - pocet radku vysledku

             %FOUND    %ISOPEN %NOTFOUND %ROWCOUNT
OPEN 
before       exception FALSE   exception exception 
after        NULL      TRUE    NULL      0

First FETCH 
before       NULL      TRUE    NULL      0
after        TRUE      TRUE    FALSE     1

Next FETCH(es) 
before       TRUE      TRUE    FALSE     1
after        TRUE      TRUE    FALSE     data dependent

Last FETCH 
before       TRUE      TRUE    FALSE     data dependent
after        FALSE     TRUE    TRUE      data dependent

CLOSE 
before       FALSE     TRUE    TRUE      data dependent
after        exception FALSE   exception exception

Vyjimka, ktera je vyvolavana, ma symbolicke jmeno INVALID_CURSOR.


Tez u implicitnich kursoru:
 
DELETE FROM emp WHERE empno = my_empno;
IF SQL%FOUND THEN -- prikaz delete byl uspesny
  INSERT INTO new_emp VALUES (my_empno, my_ename, ...);

DELETE FROM emp WHERE ...
IF SQL%ROWCOUNT > 10 THEN -- pokud jsem smazal vic nez 10 radku ...
  ...
END IF; 

-- Implicitni kurzory jsou automaticky vytvareny prikazy 
-- INSERT, DELETE, UPDATE, FORALL, SELECT INTO, COMMIT a ROLLBACK.
-- Jejich obsah se vztahuje vzdy k poslednimu prikazu.




-- Ukol c.1
-- Uvazujte tabulku katalog, ktera ma schema:
-- katalog(nazev VARCHAR2(60), vydavatel VARCHAR2(50), isbn VARCHAR2(20), porizeno DATE)
-- Cilem ukolu je katalog importovat do nasich tabulek knihy a vytisky.
-- Katalog je pristupny v tabulce xdohnal.katalog.
 
CREATE OR REPLACE PROCEDURE importuj_katalog IS
...
-- V nasledujich podukolech vzdy mente (doplnujte) tuto proceduru.


-- Ukol c.1a
-- Pomoci kurzoru vypiste nazvy knih a jejich ISBN z katalogu
-- DBMS_OUTPUT.PUT_LINE(nazev || ', ' || isbn);
--   Povolte si tisk DBMS_OUTPUT pomoci: SQL> SET SERVEROUTPUT ON





-- Ukol c.1b
-- Podle nazvu si dohledejte ID nasi knihy a to vypisujte, 
-- popr. info, ze nebyla nalezna.





-- Ukol c.1c
-- Finale: Doplnete proceduru tak, ze bude delat import.
-- Pozn: I pro vydavatele musite najit jeho ID 
--       (predpokladejte, ze vydavatel existuje)