home *** CD-ROM | disk | FTP | other *** search
/ Chip 1999 December / Chip_1999-12_cd.bin / obsahy / Chip_txt / TXT / 166.txt < prev    next >
Text File  |  1999-10-21  |  14KB  |  265 lines

  1. Databáze standardu SQL, díl 18.
  2. P²edposlední díl naτeho seriálu ze sv╪ta databází standardu SQL je zde a s ním i návod, jak pracovat s procedurami. Ale nep²edbíhejme. Nejd²íve samoz²ejm╪ dokonƒíme problematiku z dílu minulého.
  3.  
  4. Jak uloºit proceduru 
  5.  
  6. Od okamºiku, kdy jsme studovan∞ systém opustili naposledy, je uº provedením p²edchozích operací dob²e nastaven a kdokoli v n╪m bude manipulovat s daty, neporuτí jeho integritu. Tak vznikl reáln╪ ºivotaschopn∞ systém, kde ubrání jakéhokoli integritního omezení zpàsobí chybnou funkci. P²idání dalτích omezení je pl∞tváním. Následující tabulka 1 ukazuje poƒet integritních omezení tabulek podle jejich typu.
  7. Zàstaσme jeτt╪ chvíli v DDL a pokusme se vytvo²it hierarchick∞ systém p²ísluτn∞ch pohledà. První VIEW UDANICKO zobrazí pohled do vτech t²í tabulek souƒasn╪:
  8.  
  9. CREATE VIEW UDANICKO(RCU, JMENOU, PRIJMENIU, KOEU, RCO, JMENOO, PRIJMENIO, KOEO, DEN, CIC, NAZEVC, PRACHY, FINAL) AS 
  10. SELECT RCU,U.JMENO,U.PRIJMENI, U.KOEUD,RCO,O.JMENO, O.PRIJMENI,O.KOEO,DEN,CIC, NAZEVC,CENAC,CENAC*U.KOEOD*O.KOEOB FROM CIN, UDANI, CLOVEK U, CLOVEK O
  11. WHERE CIC=CICINU AND RCU=U.RC AND RCO=O.RC;
  12.  
  13. Virtuální tabulka obsahuje opravdu vτechno pot²ebné a nahrazuje tabulku UDANI. Dalτí t²i VIEW se hodí k sumárnímu pohledu na udavaƒe, jejich ob╪ti a p²eƒiny:
  14.  
  15. CREATE VIEW UDAVAC(RC, JMENO, PRIJMENI, KOEFICIENT, POCET, CELKEM, UPRAVENO)
  16. AS SELECT RCU, JMENOU, PRIJMENIU, KOEU, COUNT(*), SUM(PRACHY),SUM(FINAL)
  17. FROM UDANICKO GROUP BY RCU;
  18.  
  19. CREATE VIEW OBET(RC, JMENO, PRIJMENI, KOEFICIENT, POCET, CELKEM, UPRAVENO)
  20. AS SELECT RCO, JMENOO, PRIJMENIO, KOEO, COUNT(*), SUM(PRACHY),SUM(FINAL)
  21. FROM UDANICKO GROUP BY RCO;
  22.  
  23. CREATE VIEW PRECIN(CISLO, NAZEV, CENA, POCET, CELKEM,UPRAVENO)
  24. AS SELECT CIC, NAZEVC, PRACHY, COUNT(*), SUM(PRACHY),SUM(FINAL)
  25. FROM UDANICKO GROUP BY CIC;
  26.  
  27. Pod vlivem minul∞ch dílà seriálu snadno vytvo²íme pohledy na rodná ƒísla udavaƒà a ob╪tí:
  28.  
  29. CREATE VIEW RCUDAV(RC) AS SELECT RCU FROM UDANI GROUP BY RCU;
  30.  
  31. CREATE VIEW RCOBET(RC) AS SELECT RCO FROM UDANI GROUP BY RCO;
  32.  
  33. Poslední VIEW je pro vás mal∞m rébusem:
  34.  
  35. CREATE VIEW MEDAILE(RC, JMENO, PRIJMENI) AS
  36. SELECT RC, JMENO, PRIJMENI FROM OBET
  37. WHERE RC NOT IN RCUDAV;
  38.  
  39. Pro zavrτení trpkého humoru se vra£me do DML a zadejme n╪kolik p²íkazà SELECT, které prov╪²í dàkladnost p²edchozí p²ípravy:
  40.  
  41. SELECT TOP 10 PERCENT * FROM UDAVAC ORDER BY POCET DESC;
  42. SELECT * FROM UDANICKO WHERE RCU IN RCOBET OR RCO IN RCUDAV;
  43. SELECT COUNT(*) POCET_KUSU FROM MEDAILE;
  44.  
  45. Co jeτt╪ zb∞vá 
  46. Umíme uº pracovat s tabulkami, které obsahují data vzájemn╪ provázaná doménov∞mi, entitními a referenƒními integritami, a jsme schopni zajistit bezrozpornost uloºen∞ch dat pomocí definic tabulek v DDL. Dále víme, jak se efektivn╪ podívat do jedné nebo více tabulek pomoci VIEW. Zatím vτak nevíme, jak efektivn╪ pracovat s p²íkazy pro aktualizaci dat v tabulkách. Ideální by bylo mít moºnost formulovat jeden p²íkaz, kter∞ na serveru vyvolá spuτt╪ní jednoho nebo více p²íkazà. Naτt╪stí jazyk SQL DDL takové ²eτení p²ímo nabízí pomocí uloºen∞ch procedur. Ty mají svàj název a vnit²ní obsah tvo²en jednotliv∞mi p²íkazy. Uloºenou proceduru je moºné vytvo²it, zruτit a spustit. Po spuτt╪ní procedury se vykonají její vnit²ní p²íkazy v p²edem stanoveném po²adí podle algoritmu v procedu²e. Pokud jste jiº programovali v n╪kterém jazyce, nebude pro vás obtíºné konstruovat i sloºit╪jτí algoritmy. Na druhé stran╪ práv╪ proto nechávám uloºené procedury jako poslední téma. Pokud by ƒtená² o jejich existenci a moºnostech v╪d╪l d²íve, patrn╪ by nebyl ochoten k dekompozici systému do více tabulek a k vnímání integritních omezení a vτechno by cht╪l ²eτit algoritmicky. Cht╪l jsem zabránit tomu, aby znalci algoritmizace, ke kter∞m se také hrd╪ hlásím, nevyrazili kvapem po slepé koleji tvorby obrovsk∞ch strukturovan∞ch procedur, a to bez stop databázového myτlení. P²es to vτechno by bez uloºen∞ch procedur nebylo moºno realizovat rozumn╪ ºádn∞ databázov∞ systém. Dalτím kladn∞m rysem uloºen∞ch procedur je jejich nep²eruτitelnost. Proceduru spustíme jedním p²íkazem a ten se provede naráz, p²estoºe màºe mít sloºitou vnit²ní strukturu. Vhodná konstrukce procedur vede potom k minimalizaci kolizí s integritními omezeními a záleºí pouze na nás, jak tuto moºnost vyuºijeme. 
  47.  
  48. Procedura bez parametrà
  49. Kaºd∞ zaƒátek màºe b∞t lehk∞, je-li la£ka dostateƒn╪ nízko. Nejsnazτí je vytvo²it uloºenou proceduru, která nemá ºádné parametry. Typické jsou procedury zajiτ£ující hromadn∞ úklid. Procedura KONCIME postupn╪ zruτí data v tabulkách A, B a C. Takovou proceduru vytvo²íme v DDL p²íkazem:
  50.  
  51. CREATE PROCEDURE KONCIME
  52. AS
  53. BEGIN
  54. DELETE FROM A;
  55. DELETE FROM B;
  56. DELETE FROM C;
  57. END
  58.  
  59. Pak proceduru snadno spustíme p²íkazem:
  60.  
  61. EXECUTE PROCEDURE KONCIME;
  62.  
  63. V∞hody takové procedury jsou patrné, pokud tabulky B a C jsou ƒíselníky a tabulka A do nich odkazuje. Pak procedura KONCIME ruτí obsahy tabulek ve správném po²adí a nebudou problémy s referenƒními integritami. Dále nemusíme znát názvy pàvodních tabulek podobn╪ jako ve VIEW a do t²etice p²ístupové právo k procedu²e KONCIME nemusí mít kaºd∞ nezodpov╪dn∞ jedinec, ale nap²íklad jenom správce databáze.
  64.  
  65. Procedura se vstupními parametry
  66. Rozτí²íme moºnosti procedur o komunikaci prost²ednictvím vstupních parametrà. Kaºd∞ vstupní parametr je dán sv∞m jménem a datov∞m typem. Jejich seznam se p²i vytvá²ení procedury uvede uzav²en∞ do kulat∞ch závorek za názvem procedury. Vstupní parametry mají sice mnohdy podobné názvy a v∞znam jako jednotlivé sloupce v tabulkách, ale jsou to pouze lokální prom╪nné, které vznikají uvnit² procedury pro její vnit²ní pot²ebu. P²i volání procedury do t╪chto prom╪nn∞ch zvenku vstupují konkrétní hodnoty, které jsou uvnit² procedury pouºity jako souƒásti v∞razà. Pro rozliτení názvà sloupcà tabulek a názvà lokálních prom╪nn∞ch se pouºívá dvojteƒková konvence. Je-li p²ed názvem uvedena dvojteƒka, jde o název lokální prom╪nné. ¼asto pot²ebujeme proceduru pro ruτení osoby podle rodného ƒísla. Nejprve vytvo²íme jednoduchou proceduru:
  67.  
  68. CREATE PROCEDURE KILLER(RCX VARCHAR(10))
  69. AS
  70. BEGIN
  71. DELETE FROM CLOVEK WHERE RC=:RCX;
  72. END
  73.  
  74. Po spuτt╪ní procedury KILLER p²íkazem:
  75.  
  76. EXECUTE PROCEDURE KILLER "5511273208";
  77.  
  78. si uv╪domíme, ºe konkrétní osobu není moºné zruτit, protoºe má vazby z jin∞ch tabulek. Proto proceduru nejprve zniƒíme a vytvo²íme dokonalejτí dílo zkázy. To vτe ovτem za p²edpokladu, ºe tabulky A, B, C neobsahují zásadní informace, které je nutno uchovávat i po smrti:
  79.  
  80. DROP PROCEDURE KILLER;
  81.  
  82. CREATE PROCEDURE KILLER(RCX VARCHAR(10))
  83. AS
  84. BEGIN
  85. DELETE FROM A WHERE RC=:RCX;
  86. DELETE FROM B WHERE RCIS=:RCX;
  87. DELETE FROM C WHERE RRCCIISS=:RCX;
  88. DELETE FROM CLOVEK WHERE RC=:RCX;
  89. END
  90.  
  91. Procedury se vstupními parametry hrají zásadní roli p²i aktualizaci dat. Následující procedura je vhodná pro zm╪nu k²estního jména konkrétní osoby:
  92.  
  93. CREATE PROCEDURE KRESTNI (RCX VARCHAR(10), NOVE VARCHAR(30))
  94. AS
  95. BEGIN
  96. UPDATE CLOVEK SET JMENO=:NOVE WHERE RC=:RCX;
  97. END
  98.  
  99. K p²ejmenování konkrétní osoby pouºijeme p²íkaz:
  100.  
  101. EXECUTE PROCEDURE KRESTNI "510611030", "JOE";
  102.  
  103. Koneƒn╪ màºeme i p²idávání nového ƒlov╪ka do tabulky chápat jako proceduru zaτti£ující jeden komplikovan∞ p²ikaz:
  104.  
  105. CREATE PROCEDURE NOVY_CLOVEK (RCX VARCHAR(10), JX VARCHAR(30), VX INTEGER)
  106. AS
  107. BEGIN
  108. INSERT INTO CLOVEK (RC, JMENO, VYSKA) VALUES (:RCX,:JX,:VX);
  109. END
  110.  
  111. Volání je op╪t jednoduché:
  112.  
  113. EXECUTE PROCEDURE NOVY_CLOVEK "6104115471", "ANNIE", 9;
  114.  
  115. Procedury, které n╪co vracejí 
  116. V n╪kter∞ch p²ípadech pot²ebujeme, aby procedura vrátila zjiτt╪né hodnoty lokálních prom╪nn∞ch. P²i vytvá²ení procedury uvedeme seznam vracen∞ch prom╪nn∞ch v závorce za klíƒové slovo RETURNS. Následující pon╪kud um╪l∞, ale názorn∞ p²íklad procedury NANECO ukazuje, jak lze vytvo²it snadno souƒasn╪ druhou a t²etí mocninu celého ƒísla:
  117.  
  118. CREATE PROCEDURE NANECO (X INTEGER) RETURNS (X2 INTEGER, X3 INTEGER)
  119. AS
  120. BEGIN
  121. :X2=:X*:X;
  122. :X3=:X*:X*:X;
  123. END 
  124.  
  125. Zajímají-li nás mocniny ƒísla 7, musíme mít deklarovány dv╪ prom╪nné, nap²íklad P a Q. Potom vyvoláme proceduru p²íkazem s klíƒov∞m slovem RETURNING_VALUES p²ed v∞stupními parametry:
  126.  
  127. EXECUTE PROCEDURE NANECO 7 RETURNING_VALUES :P, :Q;
  128.  
  129. N╪kdy pot²ebujeme uvnit² procedury spustit p²íkaz SELECT tak, aby vypoƒetl dàleºité údaje z tabulek, a to nap²íklad pomocí agregaƒních funkcí. Pokud nechceme jako odpov╪╘ tabulku, pouºijeme v p²íkazu SELECT klíƒové slovo INTO aº na konci. Za ním uvedeme seznam lokálních prom╪nn∞ch, do kter∞ch má b∞t uloºen v∞sledek. Následují ukázky pouºití na procedurách NEJMENSI, KDOTOJE, UCET_TED a STAV_TED:
  130.  
  131. CREATE PROCEDURE NEJMENSI (JJJ VARCHAR(30)) RETURNS (VVV INTEGER)
  132. AS
  133. BEGIN
  134. SELECT MIN(VYSKA) FROM CLOVEK 
  135. WHERE JMENO=:JJJ
  136. INTO :VVV;
  137. END 
  138.  
  139. CREATE PROCEDURE KDOTOJE (RCX VARCHAR(10)) RETURNS (JJJ VARCHAR(30), PPP VARCHAR(30))
  140. AS
  141. BEGIN
  142. SELECT JMENO, PRIJMENI FROM CLOVEK
  143. WHERE RC=:RCX
  144. INTO :JJJ, :PPP; 
  145. END
  146.  
  147. CREATE PROCEDURE UCET_TED (CUC VARCHAR(20)) RETURNS (P DECIMAL(10,2), V DECIMAL(10,2)) 
  148. AS
  149. BEGIN
  150. SELECT SUM(CASTKA) FROM UCET WHERE CU=:CUC AND POHYB="P"
  151. INTO :P;
  152. SELECT SUM(CASTKA) FROM UCET WHERE CU=:CUC AND POHYB="V"
  153. INTO :V;
  154. END
  155.  
  156.  
  157. CREATE PROCEDURE STAV_TED(CUC VARCHAR(20)) RETURNS (STAV DECIMAL(10,2))
  158. AS
  159. DECLARE VARIABLE A DECIMAL (10,2);
  160. DECLARE VARIABLE B DECIMAL (10,2);
  161. BEGIN
  162. EXECUTE PROCEDURE UCET_TED :CUC RETURNING_VALUES :A, :B;
  163. :STAV=:A - :B;
  164. END
  165.  
  166. První t²i uvedené procedury se hodí na zjiτt╪ní nejmenτí v∞τky ƒlov╪ka podle k²estního jména, na identifikaci ƒlov╪ka z rodného ƒísla a na sumarizaci p²íjmà a v∞dajà na úƒtu. Poslední procedura pro celkov∞ stav na úƒtu je zajímavá ve dvou sm╪rech. P²edn╪ demonstruje moºnost volání procedury procedurou s uloºením dílƒích v∞sledkà do prom╪nn∞ch A, B. Dále vidíme, jak ²eτit nedostatek lokálních prom╪nn∞ch. Mezi klíƒov∞mi slovy AS a BEGIN jsou deklarovány dv╪ lokální prom╪nné A, B, které nejsou ani vstupními, ani v∞stupními parametry procedury. Zajímá-li nás stav úƒtu, staƒí se z klientu zeptat:
  167.  
  168. EXECUTE PROCEDURE STAV_TED "6674157-471/0531" RETURNING_ VALUES :ST;
  169.  
  170. V╪tvení v procedu²e
  171. Na p²edchozích p²íkladech bylo snadné pochopit princip procedur a p²edávání parametrà. Pro realizaci uºiteƒn╪jτích procedur budeme muset um╪t ²ídit postup v∞poƒtu. Zaƒneme v╪tvením, které pouºívá konstrukce IF-THEN-ELSE k podmín╪nému provád╪ní p²íkazà. Chceme-li p²idat osobu do tabulky, u které NEM╡ME OMYLEM zajiτt╪nou entitní integritu, staƒí napsat p²idávací proceduru PRIDEJ_HO:
  172.  
  173. CREATE PROCEDURE PRIDEJ_HO (RCX VARCHAR(10), JJJ VARCHAR (30))
  174. AS
  175. BEGIN
  176. IF NOT EXISTS(SELECT RC FROM CLOVEK WHERE RC=:RCX)
  177. THEN INSERT INTO CLOVEK (RC, JMENO) VALUES (:RCX, :JJJ); 
  178. END 
  179.  
  180. Pokud neexistuje v tabulce CLOVEK ani jeden ²ádek se stejn∞m rodn∞m ƒíslem jako RCX, je zaloºena nová poloºka s tímto rodn∞m ƒíslem a p²ísluτn∞m jménem JJJ. V opaƒném p²ípad╪ se ned╪je nic. Vidíte názorn╪, jak nev∞chovné jsou jednoduché p²íklady. Leckdo si te╘ pomyslí, ºe primární klíƒe a unikátní indexové soubory jsou k niƒemu. Hlavní smysl integritních omezení je v tom, ºe nás nezávisle hlídají nap²íklad i p²i spouτt╪ní nedomyτlen∞ch procedur. P²edstavte si, ºe v procedu²e PRIDEH_HO by omylem chyb╪la spojka NOT. Inteligentn╪jτí procedura PRIDEJ_INFO by mohla mít stejné parametry, ale jiné chování. V p²ípad╪ jiº existujícího rodného ƒísla RCX nebude rezignovat, ale opraví jméno ƒlov╪ka:
  181.  
  182. CREATE PROCEDURE PRIDEJ_INFO (RCX VARCHAR(10), JJJ VARCHAR (30))
  183. AS
  184. BEGIN
  185. IF NOT EXISTS(SELECT RC FROM CLOVEK WHERE RC=:RCX)
  186. THEN INSERT INTO CLOVEK (RC, JMENO) VALUES (:RCX, :JJJ);
  187. ELSE UPDATE CLOVEK SET JMENO=:JJJ WHERE RC=:RCX;
  188. END 
  189.  
  190. P²i volání procedury PRIDEJ_INFO nemusíme v╪d╪t p²edem, zda jde o nového, ƒi o starého známého. U klientu se pak set²e rozdíl mezi opravou a p²idáním dat. Pokud uvedenou techniku povaºujete za hazard, pouºívejte v╪tvení na ²eτení jin∞ch situací. Pak se vám jist╪ bude líbit procedura:
  191.  
  192. CREATE PROCEDURE ZRUS_HO (RCX VARCHAR(10))
  193. AS
  194. BEGIN
  195. IF NOT EXISTS(SELECT RC FROM UCET WHERE MAJITEL=:RCX)
  196. THEN DELETE FROM CLOVEK WHERE RC=:RCX; 
  197. END 
  198. Jaromír Kukal
  199.  
  200. Dalτí moºnosti ²ízení v∞poƒtu 
  201. Neº se pustíme do dokonƒení projektu OZNAMKA, rád bych popsal obecné moºnosti ²ízení v∞poƒtu uvnit² procedur. Nejdàleºit╪jτí je pojem bloku. BLOK je skupina p²íkazà sev²en∞ch mezi BEGIN a END. Uvnit² procedury je vºdy jeden blok tvo²ící její t╪lo. Bloky se mohou t麠zahníz╘ovat a vytvá²et tak struktury. Posloupnost p²íkazà uzav²ená do bloku se totiº nejen v SQL chová jako jeden p²íkaz. Toho vyuºíváme jak p²i v╪tvení, tak p²i cyklech. P²íkaz v╪tvení má dva obecné tvary:
  202.  
  203. IF logick∞ v∞raz 
  204. THEN p²íkaz proveden∞ nejv∞τe jednou
  205.  
  206. IF logick∞ v∞raz 
  207. THEN p²íkaz proveden∞ p²i spln╪ní podmínky
  208. ELSE opaƒn∞ p²íkaz
  209.  
  210. Logické v∞razy a p²íkazy jiº známe dávno a bloky usnadní konverzi posloupnosti p²íkazà na jeden p²íkaz.
  211.  
  212. Pro cyklus s testováním podmínky p²ed zapoƒetím práce se pouºívá schéma:
  213.  
  214. WHILE logick∞ v∞raz
  215. DO p²íkaz opakovan∞ n╪kolikrát
  216.  
  217. Pro cyklus p²es vτechny ²ádky tabulky urƒené selectem se pouºívá schéma:
  218.  
  219. FOR select p²íkaz 
  220. DO p²íkaz aplikovan∞ na ²ádek selectu
  221.  
  222. Pro oτet²ení chyb pouºijeme schéma:
  223.  
  224. WHEN ANY
  225. DO p²íkaz ƒíhající na chybu
  226.  
  227. Pro p²edƒasn∞ v∞chod z procedury pouºijeme p²íkaz EXIT. 
  228.  
  229. Pouºití cyklu, bloku a oτet²ení v∞jimek je uvedeno v následujících dvou procedurách. Procedura GAUSS ²eτí Gaussàv τkoláck∞ problém seƒtení ƒísel od 1 do N. Procedura PRUSVIH ²eτí stejn∞ problém, ale hledá nejvyττí moºné ƒíslo, pro které se v∞poƒet jeτt╪ nezhroutí. Vτimn╪te si práce s bloky a lokálními prom╪nn∞mi:
  230.  
  231. CREATE PROCEDURE GAUSS (N INTEGER) RETURNS (S INTEGER)
  232. AS
  233. DECLARE VARIABLE K INTEGER;
  234. BEGIN
  235. :K=0;
  236. :S=0;
  237. WHILE :K<=:N 
  238. DO BEGIN
  239. :S=:S+:K;
  240. :K=:K+1;
  241. END 
  242. END
  243.  
  244. CREATE PROCEDURE PRUSVIH RETURNS (K INTEGER,S INTEGER)
  245. AS
  246. DECLARE VARIABLE KNEW INTEGER;
  247. DECLARE VARIABLE SNEW INTEGER;
  248. BEGIN
  249. :K=0;
  250. :S=0;
  251. WHILE YES
  252. DO BEGIN
  253. :SNEW=:S+:K;
  254. WHEN ANY
  255. DO EXIT;
  256. :KNEW=:K+1;
  257. :S=:SNEW;
  258. :K=:KNEW;
  259. END 
  260. END
  261.  
  262. Po naƒerpání znalostí o uloºen∞ch procedurách se màºeme pustit do dokonƒení projektu a tím i seriálu v p²íτtím díle.
  263. Jaromír Kukal
  264.  
  265.