Umíme to s Delphi: 91. díl – první Interbase aplikace v Delphi

Dnešní článek vás nejprve naučí vkládat data do databázových tabulek, a to hned dvěma možnými způsoby, a následně vám krok za krokem ukáže, jak v Delphi vytvořit aplikaci pracující s databází Interbase. V závěru článku uvidíte, jak získat pomocí jednoduchého SQL dotazu komplexní data a jak tato data v aplikaci zobrazit.
Na úvod článku si připomeňme, čím jsme skončili před týdnem. Minule jsme společně vytvořili jednoduchou databázi modelující mzdovou agendu fiktivní firmy. Pak jsme spustili nástroj IBConsole a pomocí SQL skriptu vytvořili databázové tabulky. Dnes začneme tím, že do tabulek vložíme několik úvodních dat.

V tomto okamžiku tedy máme vytvořené tři databázové tabulky: Oddělení, Profese a Zaměstnanec. Vkládání dat do tabulky můžeme provést několika způsoby. Nejprve se podíváme, jaká data budeme vlastně vkládat.

Tabulka Oddělení:

Název Označení Rizikový příplatek
Výroba 100 0.1
Expedice 101 0
Marketing 102 0
Reklamační 103 0.3
Vývoj 104 0

Tabulka Profese:

Název Profesní příplatek
Svářeč 0.1
PR manažer 0.2
Programátor 0.3
Operátor 0
Kalič 0.1
Analytik 0.4
Sekretářka 0

Tabulka Zaměstnanec:

Jméno Příjmení Velikost košile Základní plat Ohodnocení Profese Oddělení
Petr Novák 42 10000 1000 Svářeč Výroba
Jiří Vokurka 40 10000 2000 Kalič Výroba
Lenka Krásná 36 20000 3000 PR manažerka Marketing
Jana Smutná 37 15000 2000 Sekretářka Expedice
Jan Bouchal 47 20000 3000 Programátor Vývoj
Marcel Starý 42 30000 5000 Analytik Vývoj

Poznámka: nezabývejte se prosím příliš sémantikou (významem) těchto dat, sám si nedovedu představit firmu, která by takhle vypadala:-), ale věřím, že to není příliš podstatné. Tato data v každém případě budeme považovat za úvodní a vložíme je do naší databáze.

Vkládání dat pomocí IBConsole

K vkládání dat do tabulek je možné použít přímo nástroj IBConsole. Na tabulce Oddělení si ukážeme, jak na to.

Spusťte tedy IBConsole, připojte se k serveru a k databázi Platy. Tyto činnosti jsou popsány v předchozích dvou dílech seriálu. Až se databáze Platy zobrazí, klepněte na Tables a v pravé části okna vidíte názvy všech tří tabulek. Nyní klepněte na tabulku Oddělení pravým tlačítkem a z kontextové nabídky vyberte Properties...

Otevře se další dialog, v němž je možné prohlížet a modifikovat vlastnosti tabulky Oddělení. Pro nás je momentálně nejpodstatnější záložka Data – přepněte se na ní. Zobrazí se prázdná tabulka (viz obrázek):

Klepněte na černou ikonu „plus“ ve spodní části okna a následně do některého pole: můžete ihned vkládat data. Pozor: při vkládání pomocí IBConsole je nutné zadávat i ID oddělení – nástroj je nedokáže generovat sám, ale hlídá, aby byly zadány. Vložíte-li do tabulky tímto způsobem výše uvedená data, bude výsledek vypadat například takto:

Nyní je velmi důležité stisknout tlačítko Commit &Refresh, aby byly data fyzicky zapsána do databáze.

Okno s tabulkou Oddělení již můžete zavřít, data jsou úspěšně vložena.

Vkládání dat pomocí SQL skriptu

Předchozí způsob vkládání dat má (kromě řady malých) jednu velmi výraznou nevýhodu: pokud bychom museli data z nějakého důvodu vkládat víckrát, musíme je vždy znovu a znovu zapisovat. Bylo by zřejmě vhodnější připravit nějaký skript, který bychom v případě nutnosti pouze použili (spustili) a který by zajistil vložení dat automaticky, bez nutnosti data vždy znovu a znovu zapisovat.

Protože hovoříme o databázi Interbase (tedy o SQL databázi), vytvoříme skript samozřejmě v jazyce SQL. Použitý skript je uveden v následujícím výpisu:

INSERT INTO profese (nazev, priplatek) VALUES (`Svářeč`, 0.1);
INSERT INTO profese (nazev, priplatek) VALUES (`PR manažer`, 0.2);
INSERT INTO profese (nazev, priplatek) VALUES (`Programátor`, 0.3);
INSERT INTO profese (nazev, priplatek) VALUES (`Operátor`, 0);
INSERT INTO profese (nazev, priplatek) VALUES (`Kalič`, 0.1);
INSERT INTO profese (nazev, priplatek) VALUES (`Analytik`, 0.4);
INSERT INTO profese (nazev, priplatek) VALUES (`Sekretářka`, 0);

INSERT INTO zamestnanec (idprofese, idoddeleni, jmeno, prijmeni, kosile, zakladniplat, ohodnoceni) VALUES (1, 1, `Petr`, `Novák`, 42, 10000, 1000);
INSERT INTO zamestnanec (idprofese, idoddeleni, jmeno, prijmeni, kosile, zakladniplat, ohodnoceni) VALUES (5, 1, `Jiří`, `Vokurka`, 40, 10000, 2000);
INSERT INTO zamestnanec (idprofese, idoddeleni, jmeno, prijmeni, kosile, zakladniplat, ohodnoceni) VALUES (2, 3, `Lenka`, `Krásná`, 36, 20000, 3000);
INSERT INTO zamestnanec (idprofese, idoddeleni, jmeno, prijmeni, kosile, zakladniplat, ohodnoceni) VALUES (7, 2, `Jana`, `Smutná`, 37, 15000, 2000);
INSERT INTO zamestnanec (idprofese, idoddeleni, jmeno, prijmeni, kosile, zakladniplat, ohodnoceni) VALUES (3, 5, `Jan`, `Bouchal`, 47, 20000, 3000);
INSERT INTO zamestnanec (idprofese, idoddeleni, jmeno, prijmeni, kosile, zakladniplat, ohodnoceni) VALUES (6, 5, `Marcel`, `Starý`, 42, 30000, 5000);

Skript spustíte v IBConsoli stejným způsobem jako skript pro vytvoření databáze (viz předchozí díl seriálu). Skript v nástroji Interactive SQL spusťte; po jeho proběhnutí se pokuste zavřít okno se skriptem. IBConsole se otáže, zda si přejete potvrdit (Commit) příslušnou transakci. Klepněte na Yes (viz obrázek) a data jsou vložena.

Prohlédněte si v IBConsoli obsah tabulek: vidíte, že všechna data jsou na svém místě.

Možná jste postřehli následující maličkost: ve skriptu vkládajícím data do tabulek Zaměstnanec a Profese se nikde nevyskytují údaje o ID příslušného záznamu. Využíváme toho, že ID je vytvářeno generátorem a vkládáno triggerem při vkládání nového záznamu do tabulky.

Abychom však v tabulce Zaměstnanec mohli uvést, v kterém oddělení ten který zaměstnanec pracuje (resp. jakou profesi vykonává), potřebujeme se odkazovat na příslušné ID oddělení (resp. ID profese). Tato ID přísně vzato neznáme (sami jsme je nevkládali a na jejich hodnoty se nemůžeme spolehnout). Prakticky je situace taková, že vkládáme-li první záznamy do nové databáze a máme-li standardně nastaveny všechny generátory, jsou jednotlivá ID generována „správně“, tj. vzestupně od jedničky s krokem 1. Z těchto důvodů si v tomto jednoduchém skriptu můžeme „dovolit“ pracovat s ID jako bychom je znali.

Je však nutné zdůraznit, že takovýto skript je velmi nepřenositelný a závislý na konkrétní situaci. Ztrácíme tím jednu z jeho hlavních výhod – možnost opakovaného spouštění. Pokud bychom chtěli skript spustit znovu, museli bychom v něm opravit všechna konkrétní ID, která jsme v něm uvedli.

Zajímá-li vás, jak napsat skript správně (byť za cenu mírně většího úsilí) – tedy tak, aby byl přenositelný a spustitelný bez ohledu na aktuální hodnoty generátorů, věnujte prosím svou pozornost následující ukázce:

INSERT INTO oddeleni (nazev, oznaceni, riziko) VALUES (`Sklad`, 200, 0);
INSERT INTO profese (nazev, priplatek) VALUES (`Skladník`, 0);
INSERT INTO zamestnanec (idprofese, idoddeleni, jmeno, prijmeni, kosile, zakladniplat, ohodnoceni) VALUES (gen_id(genprofese, 0), gen_id(genoddeleni, 0), `Karel`, `Prášil`, 40, 11000, 0);

Jinak řečeno – při vkládání zaměstnance zavoláme funkci gen_id, která slouží k vygenerování id na základě generátoru předaného jako parametr, ale zavoláme ji s krokem 0, to znamená, že v podstatě získáme naposledy vygenerovanou hodnotu příslušných ID oddělení a profese.

Také tento skript spusťte v IBConsoli, abychom měli tutéž bázi dat.

Konečně Delphi

Nyní se konečně dostáváme k nejdůležitější činnosti – vytvoření aplikace v Delphi. Nemá asi smysl dodávat, že vytvoříme databázovou aplikaci pracující s platformou Interbase a že využijeme databázi, kterou jsme právě dokončili.

V následujících odstavcích vytvoříme nejjednodušší možnou databázovou aplikaci pracující s Interbase. Nebudeme používat žádné komponenty, jejichž použití není nezbytně nutné. V příštích dílech seriálu se pak můžete těšit na podrobnější rozbor Interbase v Delphi a na popis všemožných souvisejících komponent.

1. Vytvořte novou aplikaci. Zaměřte se na záložku Interbase palety komponent a na formulář umístěte komponentu IBTable, komponentu IBDatabase a komponentu IBTransaction. Dále použijte komponentu DataSource ze záložky Data Access a tradiční komponentu DBGrid ze záložky Data Controls.

2. Budeme nastavovat vlastnosti komponent. Začneme komponentou IBDatabase. Nastavte její vlastnost DatabaseName. Pokud klepnete v Object Inspectoru na tlačítko u této vlastnosti, můžete příslušný databázový soubor (v našem případě Platy.gdb) přímo najít na disku. Pokud jste vytvářeli databázi přesně podle návodu v předminulém dílu, hledejte soubor c:\!\platy.gdb. Komponentě INDatabase dále nastavte vlastnost DefaultTransaction na IBTransaction1. Pak se pokuste nastavit vlastnost Connected na True: objeví se přihlašovací dialog (viz obrázek), do něj zadejte tradiční údaje – uživatel SYSDBA, heslo masterkey. Po potvrzení dojde k připojení k databázi.

3. Nyní budeme nastavovat komponentu IBTransaction1. Jedná se o komponentu zapouzdřující databázovou transakci a alespoň jedna tato komponenta se obvykle musí objevit v každé aplikaci Delphi pracující s databází Interbase. Vlastnost DefaultDatabase nastavte na IBDatabase1 a Active na True.

4. Další komponentou, jíž se budeme zabývat, je IBTable1, která zapouzdřuje databázovou tabulku. Nastavte vlastnost Database na IBDatabase1. Předtím, než bude možné nastavit Active na True, je nutné zvolit požadovanou tabulku. Klepnete-li v Object Inspectoru na tlačítko u vlastnosti Table Name, spatříte rozbalovací seznam dostupných tabulek – v tomto případě se objeví nám dobře známé tabulky Zaměstnanec, Oddělení a Profese. Zvolte tedy např. tabulku Zaměstnanec. Nyní můžete nastavit Active na True.

5. Předposlední komponentou je DataSource1. U ní stačí nastavit vlastnost DataSet na požadovanou datovou sadu. V našem případě je datová sada reprezentována tabulkou Zamestnanec (a tedy komponentou IBTable1), proto jako hodnotu vlastnosti DataSet vložte IBTable1.

6. Poslední, již velmi jednoduchý a notoricky známý krok spočívá v propojení dat s jejich vizuální reprezentací, tedy s komponentou DBGrid. Komponentě DBGrid tedy nastavte vlastnost DataSource na DataSource1. A je hotovo.

V komponentě DBGrid se objevily očekávané údaje – tedy kompletní obsah tabulky Zamestnanec. Následující obrázek ukazuje aplikaci v návrhové fázi (vidíte, že jsem databázové nevizuální komponenty naprosto zavržením způsobem „nastrkal“ na formulář, přestože by měly být umístěny spíše v datovém modulu, aby na formuláři nepřekážely):

Vylepšení aplikace – databázový dotaz

Zadíváte-li se na vytvořenou aplikaci, asi nebudete příliš nadšení. Výsledná mřížka je plná různých pochybných a zcela nesrozumitelných čísel a identifikátorů a skutečný význam dat by byl nezasvěceného uživatele prakticky nedekódovatelný.

Proto aplikaci vylepšíme. Namísto komponenty IBTable použijeme IBQuery a namísto tabulky Zamestnanec budeme vypisovat takové informace, které nás opravdu zajímají.

Na tomto místě bych rád ještě jednou zdůraznil, že přestože se málokterá databázová aplikace obejde bez nejrůznějších identifikátorů, klíčů a jednoznačných číselných označení, před uživatelem by měly být tyto identifikátory skryty. V ideálním případě by se neměl vůbec dozvědět, že záznamy (řádky) v tabulkách obsahují nějaké „balastní“ údaje – aplikace by měla pracovat tak, aby uživateli zobrazovala výhradně relevantní informace modelující reálný svět. Žádné dodatečné identifikátory uživatele nezajímají. Proč také?

Je zřejmé, že pokud použijeme komponentu IBTable a vypíšeme kompletní obsah tabulky, bude předchozí odstavec automaticky popřen. Proto p5idejte do aplikace komponentu IBQuery (je samozřejmě také v záložce Interbase).

Komponentě IBQuery1 nastavte tradiční vlastnost Database na IBDatabase1.

Nyní si otevřete editor vlastnosti SQL komponenty IBQuery1 a do editačního okénka zadejte třeba následující dotaz:

SELECT jmeno, prijmeni, kosile, zakladniplat + ohodnoceni as vychoziplat
FROM zamestnanec

Nezapomeňte nastavit vlastnost Active komponenty IBQuery1 na True a také „přehodit“ u komponenty DataSource datovou sadu (vlastnost DataSet) na IBQuery1.

V komponentě DBGrid se objevily požadované údaje o všech zaměstnancích

Oproti předchozímu případu (použití a zobrazení celé tabulky pomocí IBTable1) jsme dosáhli dvou vylepšení:

  • zobrazují se jen ty sloupce, o něž stojíme;
  • jednoduše jsme získali celkový výchozí plat zaměstnance jako součet základní mzdy a osobního ohodnocení.

Zatímco prvního bodu bychom mohli dosáhnout i při použití IBTable (při zobrazování tabulky můžeme nastavit, které sloupce se mají zobrazit), druhý bod by byl problematický.

Poslední věc, kterou si ukážeme v tomto díle, je zformulování databázového SQL dotazu tak, abychom se o každém zaměstnanci dozvěděli kompletní údaje – tedy profesi, oddělení a celkový plat (včetně profesního a rizikového příplatku).

Příslušný SQL dotaz bude vypadat takto:

SELECT jmeno, prijmeni, oddeleni.nazev as ODDELENI, profese.nazev as PROFESE, kosile, (zakladniplat * oddeleni.riziko + zakladniplat * profese.priplatek + zakladniplat + ohodnoceni) as PLAT
FROM zamestnanec
LEFT JOIN oddeleni ON zamestnanec.idoddeleni = oddeleni.idoddeleni
LEFT JOIN profese ON zamestnanec.idprofese = profese.idprofese
ORDER BY prijmeni ASC

Výsledek dotazu je patrný z obrázku:

Jediný (momentálně nepodstatný) problém spočívá v nepřesném (nebo možná spíše příliš přesném) zobrazování čísel, nicméně tím se zde nebudeme zabývat. Místo toho si uvedeme několik poznámek k použitému dotazu:

  • přímo v těle dotazu vyhodnocujeme matematický výraz (výpočet platu na základě údajů ze tří tabulek)
  • k tzv. spojování tabulek používáme doporučovaný zápis pomocí klíčového slova JOIN. Mohli bychom použít tradiční SELECT xxx FROM tabulka1, tabulka2 ... nicméně zápis pomocí JOIN je jednak doporučený a jednak názornější (striktně od sebe odděluje případné podmínky pro data (WHERE) od podmínek pro spojování (ON).
  • výsledek dotazu řadíme podle příjmení vzestupně (ORDER BY prijmeni ASC), přičemž ASC by nemuselo být uvedeno (vzestupné třídění je default).

Tolik pro k náplni dnešního článku. Naučili jsme se vkládat do databázových tabulek data – jak pomocí IBConsole, tak i SQL skriptem. Pak jsme společně vytvořili databázovou aplikaci v Delphi a poznali několik základních komponent, které při používání Interbase databází v Delphi potřebujeme.

V příštím dílu seriálu se podíváme na podporu Interbase/Firebird v Delphi zevrubněji, podrobně popíšeme mnohé komponenty a poznáme i další možnosti, které Delphi ve spolupráci s Interbase nabízejí.

Diskuze (6) Další článek: Konečné AVG 7 k dispozici

Témata článku: , , , , , , , , , , , , , , , , , , , , , , , , ,