Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
Programování s SQL
• interaktivní verze SQL– zadávání dotazů v operátorské konzoli
• konzole MySQL, • Oracle SQL Developer
• hostitelská verze SQL (Embedded SQL)– SQL začleněno do nějakého
programovacího jazyka• většinou staticky, tj. dotazy musí být známy při
překladu • programovací jazyk, který umožňuje používat
příkazy SQL, se nazývá hostitelský
Programování s SQL
• dynamické SQL– generování dotazu v programovacím
jazyce za běhu programu (sestaven např. dle hodnoty v políčku formuláře zadaném uživatelem)
• nadstavba SQL v SŘBD– obohacení SQL o výpočetní/procedurální
rysy programovacích jazyků v rámci SŘBD
Poznámka: – vestavěné SQL do jazyků i nadstavby mají
dnes většinou dynamický charakter
Příklady
• PL/SQL– nadstavba SQL v SŘBD Oracle odvozená
od jazyku ADA
• SPL – nadstavba v Informix
• SQL/PSM– SQL/Persistent Stored Modules– standard ISO – rozšíření SQL o procedury
a funkce používané jako „uložené procedury“ (stored procedures)
Příklady
• hostitelské SQL v jazycích– podpora v Oracle
• C, Cobol, ADA, Fortran, Pascal
– MS Access• Visual Basic
– začlenění do PHP– začlenění do Javy
• balík java.sql
PL/SQL
• program v PL/SQL se skládá z bloků
DECLARE
/* Deklarace prom ěnných, typ ů a lokálních podprogram ů. */
BEGIN
/* Výkonná sekce: procedury a SQL kód. */ /* Toto je jediná sekce, která je v bloku povinná. */
EXCEPTION
/* Oblast ošet ření výjimek */
END;
Rysy PL/SQL
• deklarace proměnných a konstant
<název_prom ěnné> <typ>;
kolik_bere NUMBER(6,2);
<název_konstanty> CONSTANT typ := hodnota;
limit CONSTANT REAL := 5000.00;
– typy mohou být „databázové“ (NUMERIC, VARCHAR) nebo „PL“ (PLS_INTEGER)
Rysy PL/SQL
• přiřazení hodnot– přímé operátorem přiřazení :=
cislo := 5;
– výsledek dotazuSELECT plat INTO kolik_bere FROM zamestnanci
WHERE cislo_zamestnance = zam_id;
– výstupní nebo vstupně-výstupní parametr procedury
Rysy PL/SQLDECLARE
prum_plat REAL;
PROCEDURE zvedni_plat (procento INT, plat IN OUT REAL) I S
BEGIN
plat := plat*(1+procento/100);
END;
BEGIN
SELECT AVG(plat ) INTO prum_plat
FROM zam;
zvedni_plat(5,prum_plat);
…
Rysy PL/SQL
• kurzory– odkazy na tzv. „pracovní oblasti“ (data), což
může být jeden nebo více řádek tabulky vybrané dotazem
– příklad explicitně deklarovaného kurzoruDECLARE CURSOR k1 IS
SELECT id, prijmeni FROM zamestnanci WHERE cislo_oddeleni = 20;
– nad kurzory jsou definovány další operace (otevření/zavření/načtení další řádky)
Řídicí struktury v PL/SQL
• podmínkyIF podmínka THEN
příkazyEND IF;
IF podmínka THEN IF podmínka THENpříkazy příkazy
ELSE ELSIF podmínka THENpříkazy příkazy
END IF; ELSIF podmínka THENpříkazy
ELSEpříkazy
END IF;
Řídicí struktury v PL/SQL
• větvení
[<<label_name>>]CASE selektor
WHEN klauzule1 THEN p říkazy;WHEN klauzule2 THEN p říkazy;...WHEN klauzulen THEN p říkazy;[ELSE sled statement ůn+1]
END CASE [label_name];
Řídicí struktury v PL/SQL
• cyklyLOOP
...
IF podmínka THEN
...
EXIT; -- vysko čí z cyklu
END IF;
END LOOP;
LOOP
...
EXIT WHEN podmínka;
END LOOP;
WHILE podmínka LOOP
příkazy
END LOOP;
Další vlastnosti
• definice modulů (modularita)– definice podprogramů
• procedury• funkce• anonymní bloky
– definice balíčků – CREATE PACKAGE• sdružují proměnné, kurzory a podprogramy
• definice objektový typů
Další vlastnosti – obsluha výjimekDECLARE...vyjimka_chybi_p EXCEPTION; -- deklarace výjimkyBEGIN
...IF provize IS NULL THEN
RAISE vyjimka_chybi_p; -- vyvolání výjimkyEND IF;bonus := (plat * 0.10) + (provize * 0.15);
EXCEPTIONWHEN vyjimka_chybi_p THEN ... -- zpracování výjimkyWHEN OTHERS THEN ... -- zpracování ost. výjim ekEND;
Triggery
• kód v PL/SQL může být uložen např. jako trigger
• trigger – spoušť– kód, který se automaticky spouští v SŘBD na
základě nějaké události• manipulace s daty – operace DELETE, INSERT,
UPDATE.• definice dat – operace CREATE, ALTER, DROP• jiná operace nad databází – např. SERVERERROR,
LOGON, LOGOFF, STARTUP, SHUTDOWN, ...
TriggeryCREATE [OR REPLACE ] TRIGGER trigger_name{BEFORE | AFTER | INSTEAD OF } {INSERT [OR] | UPDATE [OR] | DELETE} [OF col_name] ON table_name[REFERENCING OLD AS o NEW AS n] [FOR EACH ROW] WHEN (condition) DECLARE
Declaration-statementsBEGIN
Executable-statementsEXCEPTION
Exception-handling-statementsEND;
Triggery• trigger, který při změně platu vypíše původní a
nový plat a rozdíl
CREATE OR REPLACE TRIGGER display_salary_changes
BEFORE DELETE OR INSERT OR UPDATE ON customers
FOR EACH ROW
WHEN (NEW.ID > 0)
DECLARE
sal_diff number;
BEGIN
sal_diff := :NEW.salary - :OLD.salary;
dbms_output.put_line('Old salary: ' ||:OLD.salary);
dbms_output.put_line('New salary: ' ||:NEW.salary);
dbms_output.put_line('Salary difference: ' ||sal_diff);
END;
Ukázka• program, který provede odečtení částky pouze, je-li na účtu
dostatečná částka
DECLAREacct_balance NUMBER(11,2);acct CONSTANT NUMBER(4) := 3;debit_amt CONSTANT NUMBER(5,2) := 500.00;BEGINSELECT bal INTO acct_balance FROM accountsWHERE account_id = acct FOR UPDATE OF bal; -- zamkne záznamIF acct_balance >= debit_amt THEN
UPDATE accounts SET bal = bal - debit_amtWHERE account_id = acct;
ELSEINSERT INTO temp VALUES
(acct, acct_balance, 'Insufficient funds');END IF;COMMIT;END;
• SQL PSM – Persistent Store Modules– rozšiřuje SQL na výpočetní úplnost– umožňuje definovat tzv. uložené procedury a
funkce– první zmínka - 1994– rozlišuje externí uložené procedury (jiný
jazyk, běžící mimo server) a SQL procedury– příklad byl již v přednášce o SQL99
SQL PSM
• tabulka ucty(cislo,zustatek)
• procedura vrátí zůstatek na účtu do parametru zu
CREATE PROCEDURE vrat_zustatek
(IN c_uctu INTEGER, OUT zust DOUBLE PRECISION)
BEGIN
SELECT zustatek INTO zust
FROM ucty WHERE cislo = c_uctu;
IF zustatek < 2500 THEN SIGNAL nizky_zustatek
END IF
END
Definice procedury
CREATE FUNCTION vrat_zustatek
(IN c_uctu INTEGER) RETURNS DOUBLE PRECISION
BEGIN
DECLARE zust DOUBLE PRECISION;
SELECT zustatek INTO zust
FROM ucty WHERE cislo = c_uctu;
IF zustatek < 2500 THEN SIGNAL nizky_zustatek
END IF;
RETURN zust
END
Definice funkce
Hostitelská verze SQL v jazyce CPrincip• do zdrojového kódu v C/C++ se zapíší
speciálně uvozené dotazy SQL– zpravidla s příponou .pc
• speciální prekompilátor Pro*C/C++ (proc v Linuxu) nahradí tyto dotazy voláním funkcí ze standardní knihovny run-time (SQLLIB) a převede soubor .pc do "čistého" C/C++
• dále se kód překládá jako „obyčejný“ zdrojový kód C/C++.
• na konci se k němu linkuje knihovna SQLLIB
Psaní dotazů SQL do kódu v C
1. všechny dotazy SQL jsou uvozeny direktivou
EXEC SQL
a končí středníkem „;“
2. proměnných používané v SQL musí být uvozeny dvojtečkou „:“
Psaní dotazů SQL do kódu v CSELECT
EXEC SQL BEGIN DECLARE SECTION;
int plat_sefa;
EXEC SQL END DECLARE SECTION;
/* ... */
EXEC SQL SELECT plat INTO :plat_sefa
FROMZamestnanci WHEREid_zam = 123;
/* ... */
printf("Sefuv plat: %d \n", plat_sefa);
Psaní dotazů SQL do kódu v CINSERT
typedef struct { int id;
cha r name[20];
} rec;
EXEC SQL BEGIN DECLARE SECTION;
Myrec rec;
EXEC SQL END DECLARE SECTION;
Myrec.id=5;
strcpy(Myrec.name,"Novak");
EXEC SQL INSERT INTO Lide VALUES (:Myrec);
Deklarativní část
• deklarace se uvádějí meziEXEC SQL BEGIN DECLARE SECTION;
EXEC SQL END DECLARE SECTION;
– definují se zde hostitelské proměnné (host variables), které se budou používat pro komunikaci mezi programem a databází (načítání dat i zápis, indikátory)
Typy hostitelských proměnných
• char , int , short , long, float , double
• VARCHAR[n]
– „pseudotyp“ pro řetězce, rozpoznávaný přímo prekompilátorem Pro*C/C++
– struktura v C se 2 položkami:• arr – pole charů• len – délka pole
Implicitní konverze
SQL Pro*C/C++
VARCHAR VARCHAR[n], char
DATE VARCHAR[n], char
INTEGER int
NUMBER(P,S) char, short, int, long, float, double, char[n], VARCHAR[n]
CHAR(X) char[n],VARCHAR[n],int,short,long,float,double
Spojení s databází
EXEC SQL BEGIN DECLARE SECTION;
char username[20];
char password[20];
EXEC SQL END DECLARE SECTION;
strcpy(username, "uzivatel");
strcpy(password, "heslo");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
/* práce s databází */
EXEC SQL COMMIT WORK RELEASE;
/* potvrzení zm ěn, odpojení */
Ukončení transakcí
• ukončení transakce bez odpojeníEXEC SQL COMMIT;
• storno změnEXEC SQL ROLLBACK;
• ukončení transakce s odpojenímEXEC SQL COMMIT WORK RELEASE;
• storno změn s odpojenímEXEC SQL ROLLBACK WORK RELEASE;
Ošetření chyb
• pomocí indikátorových prom ěnných– proměnné typu short, deklarovány v deklarační
sekci stejně jako hostitelské proměnné– jsou svázané vždy s jednou konkrétní
hostitelskou proměnnou– indikují, co je v hostitelské proměnné obsaženo
za hodnotu (NULL flags, ořezání řetězce)– v rámci dotazů SQL jsou také uvozeny „:“– následují vždy bezprostředně za příslušnou
hostitelskou proměnnou
Ošetření chyb
EXEC SQL SELECT plat INTO :plat_sefa : plat_sefa_id
FROM Zamestnanci
WHERE id_zam = 123;
/* ... */
if (plat_sefa_id == 0)
printf("Plat: %d \n", plat_sefa);
Návratové kódy v indikátorových proměnných pro SELECT
Indikátor Hostitelská prom ěnná
-1 nedefinovaná hodnota (NULL v databázi)
0 korektní naplnění
-2 vkládaná hodnota je větší než proměnnáa není možné určit skutečnou velikost
>0 vkládaná hodnota je větší než proměnná,skutečná velikost je hodnota indikátoru
Návratové kódy v indikátorových proměnných pro INSERT
Indikátor Databáze
-1 uložena hodnota NULL
>=0 korektní naplnění
Ošetření chyb
• rozšíření:EXEC SQL WHENEVER podmínka akce
– pokud je splněna podmínka, provede se akce
• podmínky:– NOT FOUND
• kritériu SELECT/FETCH neodpovídá žádná položka
– SQLERROR• nějaký příkaz SQL EXEC skončil chybou
Ošetření chyb
– SQLWARNING• nějaký příkaz SQL EXEC skončil s varováním
• akce– CONTINUE
• pokud lze, pokusí se program pokračovat dalším příkazem
– DO <cmd>• vykoná se příkaz <cmd>, typicky volání funkce / exit
– GOTO <navesti>• skok na dané návěští
Ošetření chyb
– STOP• volání exit(), ukončení programu, nepotvrzené akce
jsou stornovány (rollback)
EXEC SQL WHENEVER NOT FOUND tisk_chyby();
EXEC SQL SELECT studentname INTO :st_name
FROM student
WHERE studentid = :id;
printf("Jmeno: %s.\n", st_name);
SQL v PHP
• původně Personal Home Page• od 1997 PHP Hypertext Preprocessor• skriptovací jazyk na straně serveru
založený syntakticky na jazycích C, Java, Perl (interpretovaný), používá se pro dynamické generování WWW stránek
• je volně dostupný a nezávislý na platformě
• má rozsáhlou knihovnu funkcí– práce s řetězci, umí přistupovat k databázím
pomocí SQL
Historie
• 1994 - 1995– Rasmus Lerdorf – sada skriptů v Perlu ke
zpracování záznamů o přístupech na server
• 1997– rozšíření funkčnosti, implementace v
jazyce C - PHP/FI nebo PHP2– PHP3 - Andi Gutmans a Zeev Suraski
• 2000– PHP4 – interpret zvaný Zend Engine– autoři Andi Gutmans a Zeev Suraski– objekty
• 2004– PHP5– jádro Zend Engine 2.0– výjimky, jmenné prostory– listopad 2011 – uvolněna verze PHP5.4 RC1
• verze 6 nebyla oficiálně vydána• 2015
– prosinec: verze PHP7.0– 64 bitová
Zápis PHP skript ů
• skripty se zapisují do HTML stránky mezi značky <? ?>
Příklad:<?php if (date("A")=="AM")
{ echo "Dobré ráno!"; }
else
{ echo "Dobré odpoledne!"; }
/* date("A") vrátí AM nebo PM */
?>
SQL v PHP• PHP podporuje rozhraní API pro přístup
k velkému počtu databází pomocí SQL (Oracle, Sybase, MySQL)
Základní kostra práce s databázemi:• vytvoření připojení k databázi• zaslání SQL příkazu k provedení• zpracování výsledku• odpojení od databáze
Příklad:
$spojeni = mysqli_connect("localhost",
"jméno", "heslo","databaze");
if (mysqli_connect_errno($spojeni))
{
echo "Nepoda řilo se p řipojit k MySQL. <BR>\n";
}
else
{
@$vysledek = mysqli_query($spojeni, "SELECT * FROM
Zamestnanci ORDER BY Jmeno");
if (!$vysledek){echo "Došlo k chyb ě p ři zpracování dotazu v
databázi.<BR>\n";}else{
echo "V tabulce Zamestnanci je ".mysqli_num_rows($vysledek)." záznam ů.<BR>\n";
while ($zaznam = mysqli_fetch_array($vysledek)){
echo $zaznam['OsobniCislo']." ".$zaznam['Jmeno']."<BR>";}mysqli_close($spojeni);
}}
Příklad – databáze uživatelů a přihlašovací formulář
– create table users (uname VARCHAR(20), pass VARCHAR(20);
Přihlašovací formulář<form action="login.php">
<fieldset style="width:300px"><legend> P řihlášení </legend><table align="center">
<tr><TD>Uživatelské jméno:</td><TD><INPUT TYPE=TEXT NAME=jmeno></td>
</tr> <TR><TD>Heslo:</td>
<TD><INPUT TYPE=password NAME=heslo></td></tr> <tr><td align="center" colspan="2"><button type="submit">Odeslat</button></td>
</TABLE></FIELDSET>
</form>
login.php<?php
$jmeno=$_GET["jmeno"];$heslo=$_GET["heslo"];
if($jmeno == ''){
echo '<h1 align="center">Nezadal jste žádné jméno</ h1>';exit();
}
$spojeni = mysqli_connect('localhost', '', '', 'uka zka');
if (mysqli_connect_errno($spojeni)){echo "Nepoda řilo se p řipojit k MySQL. <BR>\n";}else
login.php{
$vysledek = mysqli_query($spojeni, 'SELECT * FROM u sers WHERE uname = \''. $jmeno .'\';');if (!$vysledek){
echo "Došlo k chyb ě p ři zpracování dotazu v databázi.<BR>";mysqli_close($spojeni);exit();
}else{
if(!$zaznam = mysqli_fetch_array($vysledek)){
echo '<h1 align="center">Vaše uživatelské jméno nen í v databázi</h1>';
mysqli_close($spojeni);exit();
}else{
if($zaznam['pass']!=$heslo)
login.php{ echo '<h1 align="center">Nesprávné heslo</h1>';
mysqli_close($spojeni);exit();
} else{
$_SESSION['logged_in']=TRUE;$vysledek = mysqli_query($spojeni, 'SELECT * FROM infousers WHERE uname
= \''. $jmeno .'\';');if ($vysledek && $zaznam = mysqli_fetch_array($vysledek) ){
echo '<h1 align="center">Vaše kontaktní údaje</h1>';echo '<hr/>';echo $zaznam['jmeno'].' '. $zaznam['prijmeni'].'<br>';echo $zaznam['ulice'].'<br>';echo $zaznam['psc']. " " . $zaznam['mesto'].'<br>';echo 'e-mail: '. $zaznam['email'].'<br>';
}}
}} mysqli_close($spojeni);