Vnořené SQL ( embedded SQL) Dotazovací jazyky I
description
Transcript of Vnořené SQL ( embedded SQL) Dotazovací jazyky I
VNOŘENÉ SQL(EMBEDDED SQL)
DOTAZOVACÍ JAZYKY I
Jan SequensMFF UK, ak. rok 2009/2010
Použité zdroje
Chapter 6: Embedded SQL, Pro*C/C++ Precompiler Programmer’s guide, Release 9.2, Oracle Corporation http://download.oracle.com/docs/cd/B10501_01/
appdev.920/a97269/pc_06sql.htm Chapter 13: Application Programming I: Embedded
SQL, A Guide to DB2, 4/e, C J Date, Colin J White Embedded SQL : Introduction to Pro*C, Ankur Jain
and Jeff Ullman http://infolab.stanford.edu/~ullman/fcdb/oracle/or-
proc.html Embedded SQL v C/C++, Kateřina Opočenská
http://www.ms.mff.cuni.cz/~kopecky/vyuka/oracle2/ora2_opoc.pdf
Obsah této prezentace
Co je vnořené SQL a jak se používá Hostitelské a indikátorové proměnné Příkazy INSERT, UPDATE, DELETE,
SELECT Kurzory Ošetření chyb
Co a k čemu je vnořené SQL? Způsob použití SQL v programovacích
jazycích SQL vepsané ve zdrojovém kódu jiného
programovacího jazyka Všechny příkazy interaktivního SQL jdou
použít ve vnořeném SQL
Co a k čemu je vnořené SQL? Způsob použití SQL v programovacích
jazycích SQL vepsané ve zdrojovém kódu jiného
programovacího jazyka Všechny příkazy interaktivního SQL jdou
použít ve vnořeném SQL (nikoliv naopak)
Jak vnořené SQL používáme? Náš databázový systém musí mít
podporu vnořeného SQL v našem programovacím jazyce
Jak vnořené SQL používáme?
IBM DB2
Oracle
Microsoft SQL Server
MySQL
Jak vnořené SQL používáme?
IBM DB2
C/C++, COBOL, FORTRAN, REXX
Oracle
Microsoft SQL Server
MySQL
Jak vnořené SQL používáme?
IBM DB2
C/C++, COBOL, FORTRAN, REXX
Oracle
Ada, C/C++, COBOL, Fortran, Pascal, PL/1
Microsoft SQL Server
MySQL
Jak vnořené SQL používáme?
IBM DB2
C/C++, COBOL, FORTRAN, REXX
Oracle
Ada, C/C++, COBOL, Fortran, Pascal, PL/1
Microsoft SQL Server
Od verze 2008 ukončena oficiální podpora
MySQL
Jak vnořené SQL používáme?
IBM DB2
C/C++, COBOL, FORTRAN, REXX
Oracle
Ada, C/C++, COBOL, Fortran, Pascal, PL/1
Microsoft SQL Server
Od verze 2008 ukončena oficiální podpora
MySQL
Nepodporováno
Jak vnořené SQL používáme? Příklad vnořeného SQL (Oracle a C):
#include <stdio.h>
#include <sqlca.h>
int main(void)
{
EXEC SQL INSERT INTO osoby (prijmeni) VALUES (‘Sequens’);
return 0;
}
Jak vnořené SQL používáme? Vložíme hlavičkový soubor struktury SQL
Communication Area (SQLCA) Příkazy vnořeného SQL začínáme
direktivou EXEC SQL a ukončujeme středníkem
Jak vnořené SQL používáme? Oracle prostředí pro SQL vnořené v C/C+
+ se nazývá Pro*C/C++ Zdrojové soubory s příponou *.pc Prekompilátor Pro*C/C++ přeloží *.pc na
čistý C/C++ kód Nahrazení konstrukcí vnořeného SQL
voláními standardní run-time knihovny C/C++ kód je standardně zkompilován
Hostitelské proměnné
Předávání dat mezi SQL a C/C++ Ve vnořeném SQL označujeme
dvojtečkou Vstupní
EXEC SQL INSERT INTO osoby (prijmeni) VALUES (:prijmeni_osoby);
Výstupní EXEC SQL SELECT prijmeni
INTO :prijmeni_osoby FROM osoby;
Indikátorové proměnné
Motivace: Co uložit do proměnné, když SELECT vrátí NULL?
Řešení: Použijeme druhou, „spřátelenou“ proměnnou, která bude indikovat, jak a zda je původní proměnná naplněna
Indikátorová proměnná se zapisuje bezprostředně za původní proměnnou, oddělená dvojtečkou
Indikátorové proměnné u výstupních proměnnýchIndikátorová proměnná Hostitelská proměnná
-2 Oříznutá hodnota z databáze, hodnota se do hostitelské proměnné nevejde a její velikost nemůže být určena.
-1 Nedefinovaná hodnota, v databázi byla NULL.
0 Hodnota z databáze, není to NULL.
>0 Oříznutá hodnota z databáze, hodnota se do hostitelské proměnné nevejde. Indikátorová proměnná obsahuje velikost hodnoty v databázi.
Indikátorové proměnné u výstupních proměnných - příklad
EXEC SQL SELECT pocet_deti INTO :pocet:ind_pocet FROM osoby WHERE prijmeni = ‘Sequens’;
if (ind_pocet == -1) /* NULL v databázi */
pocet = 0;
Indikátorové proměnné u vstupních proměnných Ovlivní, co se zapíše do databáze v
příkazech INSERT nebo UPDATE
Indikátorová proměnná Zápis do databáze
-1 Zapíše se NULL (hodnota hostitelské proměnné se bude ignorovat).
>= 0 Zapíše se hodnota hostitelské proměnné.
Příkaz INSERT
Stejné použití jako při interaktivním SQL Skutečný zápis proveden až po zapsání
změn příkazem COMMIT
EXEC SQL INSERT INTO osoby (jmeno, prijmeni)
VALUES (:jmeno_osoby, :prijmeni_osoby);
Příkaz UPDATE
Stejné použití jako při interaktivním SQL Skutečný zápis proveden až po zapsání
změn příkazem COMMIT
EXEC SQL UPDATE osoby
SET jmeno = :jmeno_osoby
WHERE prijmeni = :prijmeni_osoby;
Příkaz DELETE
Stejné použití jako při interaktivním SQL Skutečné smazání provedeno až po
zapsání změn příkazem COMMIT
EXEC SQL DELETE FROM osoby
WHERE prijmeni = :prijmeni_osoby;
Příkaz SELECT
V zásadě stejné použití jako u interaktivního SQL
Je třeba vyřešit, kam a jak uložíme to, co SELECT vrátí
Příkaz SELECT
Víme-li, že náš SELECT vrátí nejvýše jeden řádek, je situace jednoduchá
Příkaz SELECT
Víme-li, že náš SELECT vrátí nejvýše jeden řádek, je situace jednoduchá
EXEC SQL SELECT jmeno, prijmeni
INTO :jmeno_osoby, :prijmeni_osoby
FROM osoby;
Příkaz SELECT
Víme-li, že náš SELECT vrátí nejvýše jeden řádek, je situace jednoduchá
EXEC SQL SELECT jmeno, prijmeni
INTO :jmeno_osoby, :prijmeni_osoby
FROM osoby;
Vrací-li SELECT více než jeden řádek, je třeba použít ke zpracování výsledku tzv. kurzor
Kurzor
Nástroj pro práci s množinou řádků, kterou vrací příkaz SELECT
Udržuje ukazatel na aktuální zpracovávaný řádek
Princip práce s kurzorem
DECLARE CURSOR Určení SQL dotazu, se kterým bude kurzor
pracovat OPEN
Provedení SQL dotazu, se kterým kurzor pracuje
FETCH Načtení jednoho řádku z výsledku dotazu
CLOSE Ukončení práce s kurzorem
DECLARE CURSOR
Pojmenování kurzoru Asiociace s dotazem
EXEC SQL DECLARE osoby_kurzor CURSOR FOR
SELECT jmeno, prijmeni
FROM osoby
WHERE pocet_deti > :minimalni_plodnost;
DECLARE CURSOR
Pojmenování kurzoru Asiociace s dotazem
EXEC SQL DECLARE osoby_kurzor CURSOR FOR
SELECT jmeno, prijmeni
FROM osoby
WHERE pocet_deti > :minimalni_plodnost;
Nezahrnujeme klauzuli INTO
OPEN
Navázání hostitelských proměnných Vykonání dotazu
EXEC SQL OPEN osoby_kurzor;
FETCH
Načtení řádku z výsledku Posunutí ukazatele na další řádek
EXEC SQL FETCH osoby_kurzor
INTO :jmeno_osoby, :prijmeni_osoby;
FETCH
Načtení řádku z výsledku Posunutí ukazatele na další řádek
EXEC SQL FETCH osoby_kurzor
INTO :jmeno_osoby, :prijmeni_osoby;
Klauzule INTO se použije zde, nikoliv v deklaraci kurzoru
Kurzor musí být deklarován a otevřen.
CLOSE
Uzavře kurzor, uvolní zdroje. Posunutí ukazatele na další řádek
EXEC SQL CLOSE osoby_kurzor;
Ošetření chyb
Ke smysluplnému příkladu použití kurzoru nám chybí způsob, jak ošetřit chyby
První možnost je testovat po každém vnořeném SQL příkazu, zda-li nedošlo k chybě, tzv. explicitní testování
Druhá možnost je implicitní testování pomocí příkazu WHENEVER
Explicitní ošetření chyb
Po vykonání každého vnořeného SQL příkazu obsahuje struktura SQLCA v poli sqlcode kontrolní hodnotu
Hodnota sqlcode Výsledek posledního příkazu
0 Proběhl v pořádku
> 0 Proběhl, ale „s problémy“ (warning). Např. hodnota 100 značí, že nebyla nalezena žádná data.
< 0 Skončil chybou (error).
Implicitní ošetření chyb
Zjednodušení oproti explicitnímu ošetření
Není třeba testovat po každém příkazu, testovací podmínka platí až do určení podmínky nové
Zajištění příkazem WHENEVER se syntaxí:
EXEC SQL WHENEVER <podmínka> <akce>;
Příkaz WHENEVER
EXEC SQL WHENEVER <podmínka> <akce>; Kde <podmínka> je
NOT FOUND (sqlcode je 100, prázdná data), SQLWARNING (varování jiné než prázdná data), SQLERROR (chyba),
A <akce> je CONTINUE (program se pokusí pokračovat) DO <volání_funkce> (zavolání C/C++ funkce) GO TO <návěští> (odskok) STOP (program ihned skončí)
Kurzory – příklad použití
EXEC SQL DECLARE osoby_kurzor CURSOR FOR
SELECT jmeno FROM osoby
WHERE pocet_deti = :minimalni_plodnost;
EXEC SQL OPEN osoby_kurzor;
EXEC SQL WHENEVER NOT FOUND DO break;
while(1)
{
EXEC SQL FETCH emp_cursor INTO :jmeno_osoby;
}
EXEC SQL CLOSE osoby_kurzor;
Kurzory FOR UPDATE
Kurzory sloužící také pro úpravu či mazání záznamů v tabulce
Kurzor je deklarován s klauzulí FOR UPDATE OF <jméno_tabulky> na konci
Příkazy UPDATE či DELETE ho mohou využít v části WHERE, byl-li již kurzor otevřen a proveden příkaz FETCH EXEC SQL UPDATE … WHERE CURRENT OF osoby_kurzor;
Odkaz na poslední záznam získaný příkazem FETCH
Posuvné (scrollable) kurzory
Dovolují i jiný pohyb ve vybraných záznamech než jen o jeden záznam vpřed
Posuvné (scrollable) kurzory
Dovolují i jiný pohyb ve vybraných záznamech než jen o jeden záznam vpřed FETCH FIRST FETCH LAST FETCH PRIOR FETCH NEXT FETCH CURRENT FETCH RELATIVE n FETCH ABSOLUTE n
Závěrečný příklad (1/4)
#include <stdio.h>
/* deklarace hostitelských proměnných */ char userid[12] = "SCOTT/TIGER";char jmeno_zamestnance[10];int cislo_zamestanance;int cislo_oddeleni; char temp[32];void sql_error(); /* SQL Communications Area */ #include <sqlca.h> main() { emp_number = 7499;/* ošetření chyb */ EXEC SQL WHENEVER SQLERROR do sql_error("Oracle chyba");
Závěrečný příklad (2/4)
/* připojení k Oracle databázi */ EXEC SQL CONNECT :userid; printf(„Pripojeno.\n"); /* deklarace kurzoru */ EXEC SQL DECLARE zam_kurzor CURSOR FOR SELECT prijmeni FROM zam WHERE cislo_oddeleni = :cislo_oddeleni; printf(„Cislo oddeleni? "); gets(temp); dept_number = atoi(temp); /* otevření kurzoru a vykonání dotazu */ EXEC SQL OPEN zam_kurzor;
Závěrečný příklad (3/4)
printf(„Prijmeni zamestnance\n"); printf("-------------\n");/* načtení dat ve smyčce pomocí FETCHopuštění smyčky, když nebude další řádek */ EXEC SQL WHENEVER NOT FOUND DO break; while (1) { EXEC SQL FETCH zam_kurzor INTO :jmeno_zamestnance; printf("%s\n", jmeno_zamestnance); } EXEC SQL CLOSE zam_kurzor; EXEC SQL COMMIT WORK RELEASE; exit(0); }
Závěrečný příklad (4/4)
void sql_error(msg)char *msg;{ char buf[500]; int buflen, msglen;
EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL ROLLBACK WORK RELEASE; buflen = sizeof (buf); sqlglm(buf, &buflen, &msglen); printf("%s\n", msg); printf("%*.s\n", msglen, buf); exit(1); }
Konec prezentace
Čas pro čarokrásnou referující Šárku