17. Práce s dotazy

Tato kapitola popisuje komponentu datové množiny TQuery, která umožňuje používat příkazy SQL k zpřístupňování dat. Předpokládá se, že jsme se již seznámili s obecným popisem datové množiny v kapitole 6.
Komponenta dotazu zaobaluje příkaz SQL, který je použit v klientské aplikaci k získávání, vkládání, aktualizaci a rušení dat z jedné nebo více databázových tabulek. SQL je jazykem průmyslového standardu relačních databází, který je používán databázemi založenými na serveru, jako je Sybase, Oracle, InterBase a Microsoft SQL Server. Komponenty dotazu mohou být použity se vzdálenými databázovými servery (pokud naše verze C++ Builderu obsahuje SQL links), s Paradoxem, dBASE, FoxPro a Access a s databázemi podporujícími ODBC.
V této kapitole se budeme zabývat body:

Efektivní používání dotazů

K efektivnímu používání komponenty dotazu se musíme seznámit s: Pokud se zabýváme vývojem desktopu a přecházíme na aplikace založené na serveru, pak se podívejte do Dotazy pro vývojáře desktopu na úvod k dotazům před přečtením zbytku této kapitoly.
Pokud jsme vývojářem databázového serveru, ale je pro nás nové budování klientů pomocí C++ Builderu, pak již dobře známe SQL a náš server, ale nejsme seznámeni s BDE. Podívejte se na Dotazy pro vývojáře serveru na úvod k dotazům a BDE před přečtením zbytku této kapitoly.
V tomto bodě se budeme zabývat:
Dotazy pro vývojáře desktopu
Jako vývojář desktopu jsme seznámeni s výrazy tabulka, záznam a položka používanými C++ Builderem a BDE. Umíme používat komponentu TTable k získání přístupu ke všem položkám v každém záznamu v datové množině. Víme, že když nastavíme vlastnost TableName pak specifikujeme databázovou tabulku ke které přistupujeme.
K omezení počtu dostupných záznamů pro naší aplikaci používá TTable metodu pro určení rozsahu a vlastnost filtru. Aplikací rozsahu dočasně omezíme datový přístup na blok záznamů souvislých indexů, které vyhovují zadané hraniční podmínce, jako je návrat všech záznamů pro zaměstnance jejichž jména jsou větší nebo rovna Jones a menší nebo rovna Smith. Nastavením filtru dočasně omezíme datový přístup na množinu záznamů, které obvykle nejsou sousední a splňují filtrovací kritérium, jako je návrat pouze těch zákazníků, které žijí v Kalifornii.
Dotazy se chovají v mnoha způsobech jako filtr, s výjimkou, že používají vlastnost SQL komponenty dotazu (a někdy vlastnosti Params) k identifikaci záznamů v datové množině k získání, vložení, zrušení nebo aktualizaci. V některých možnostech dotaz je užitečnější než filtr, protože usnadňuje přístup: Dotazy mohou být neměnné nebo mohou obsahovat nahraditelné parametry. Dotazy, které používají parametry se nazývají parametrizované dotazy. Když používáme parametrizované dotazy, pak aktuální hodnoty přiřazené k parametrům jsou vloženy do dotazu pomocí BDE před provedením nebo spuštěním dotazu. Používání parametrizovaných dotazů je značně flexibilní, protože můžeme měnit pohled uživatele a přistupovaná data za běhu bez nutnosti modifikace příkazu SQL.
Nejčastější použití dotazů v našich aplikacích je k výběru dat, které uživatel vidí, stejně jako když použijeme komponentu tabulky. Dotazy ale také mohou provádět operace aktualizace, vkládání a rušení místo získávání záznamů pro zobrazení. Když použijeme dotaz k provedení operace vložení, aktualizace nebo zrušení, pak dotaz nevrací záznamy. Tím se dotazy liší od tabulek.
Více informací o vlastnosti SQL k zápisu příkazů SQL, o používání parametrů a provádění dotazu bude uvedeno v dalších bodech této kapitoly.
Dotazy pro vývojáře serveru
Jako vývojář serveru se musíme dobře seznámit s SQL a s možnostmi našeho databázového serveru. Dotaz je pro nás SQL příkaz, který používáme pro přístup k datům. Musíme znát jak používat příkaz a jak s ním používat volitelné parametry.
Příkaz SQL a jeho parametry jsou nejdůležitější částí komponenty dotazu. Vlastnost SQL komponenty dotazu je použita k poskytnutí příkazu SQL pro přístup k datům a vlastnost Params komponenty je volitelné pole parametrů k vložení do dotazu. Komponenta dotazu je ale mnohem více než její příkaz SQL a jeho parametry. Komponenta dotazu je také rozhraní mezi naší klientskou aplikací a BDE.
Klientská aplikace používá vlastnosti a metody komponenty dotazu k manipulaci s příkazem SQL a s jeho parametry, ke specifikaci dotazované databáze, k přípravě a zrušení připravených příkazů s parametry a k provádění dotazu. Metody komponenty dotazu volají BDE, které zpracovávají požadavky našeho dotazu a komunikují s databázovým serverem, obvykle prostřednictvím ovladačů SQL Links. Server předává výsledkovou množinu (je-li) zpět BDE a BDE ji vrací naší aplikaci prostřednictvím komponenty dotazu.
Když pracujeme s komponentou dotazu, pak musíme znát terminologii používanou k popisu služeb BDE, protože se liší od terminologie používané programátory SQL databází. Např. BDE často používá termín alias (přezdívka) k odkazování na zkrácené jméno pro cestu k databázovému serveru. Přezdívka BDE je uložena v konfiguračním souboru a je nastavena ve vlastnosti DatabaseName komponenty dotazu. Můžeme stále používat přezdívky tabulek nebo korelační jména tabulek v našich SQL příkazech.
Podobně BDE se často odkazuje na dotazy používající parametry jako na parametrizované dotazy, které jsou známější jako příkazy SQL používající svázané proměnné.
Více informací o používání vlastnosti SQL, o používání parametrů, přípravě a provádění dotazů bude uvedeno v následujících bodech.

Ke kterým databázím můžeme přistupovat komponentou dotazu?

Komponenta TQuery může přistupovat k datům v: C++ Builder také podporuje heterogenní dotazy na více než jednom serveru nebo typu tabulky (např. data z tabulky Oracle a tabulky Paradoxu). Když vytváříme heterogenní dotaz, pak BDE používá Lokální SQL ke zpracování dotazu.

Seznámení s používáním komponent dotazu

K použití komponenty dotazu v aplikaci musíme při návrhu provést tyto kroky:
  1. Umístíme komponentu dotazu ze stránky DataAccess Palety komponent do datového modulu a nastavíme její vlastnost Name přijatelně pro naší aplikaci.
  2. Nastavíme vlastnost DatabaseName komponenty na jméno dotazované databáze. DatabaseName může být přezdívka BDE, explicitní adresářová cesta (pro lokální tabulky) nebo hodnota z vlastnosti DatabaseName komponenty TDatabase v aplikaci.
  3. Ve vlastnosti SQL komponenty specifikujeme příkaz SQL a nepovinně specifikujeme libovolné parametry pro příkaz ve vlastnosti Params.
  4. Pokud data dotazu mají být použity vizuálními datovými ovladači, pak umístíme komponentu datového zdroje ze stránky Data Access Palety komponent do datového modulu a nastavíme její vlastnost DataSet na jméno komponenty dotazu. Komponenta datového zdroje je použita k návratu výsledku dotazu (nazvaného výsledková množina) z dotazu do datových ovladačů pro zobrazení. Připojení datových ovladačů k datovému zdroji provedeme jejich vlastnostmi DataSource a DataField.
  5. Aktivujeme komponentu dotazu. Pro dotazy, které vracejí výsledkovou množinu použijeme vlastnost Active nebo metodu Open. Pro dotazy, které provádějí pouze akci na tabulce a nevrací výsledkovou množinu, použijeme metodu ExecSQL.
K prvnímu provedení dotazu za běhu provedeme tyto kroky:
  1. Komponentu dotazu uzavřeme.
  2. Do vlastnosti SQL vložíme příkaz SQL (pokud nebyl nastaven již při návrhu nebo chceme-li změnit již poskytnutý příkaz SQL). Při použití příkazu z návrhu tento krok přeskočíme.
  3. Nastavíme parametry a hodnoty parametrů ve vlastnosti Params přímo nebo použitím metody ParamByName. Pokud dotaz neobsahuje parametry nebo parametry nastavené při návrhu se nemění, pak tento krok přeskočíme.
  4. Voláme Prepare k inicializaci BDE a spojení hodnoty parametrů v dotazu. Volání Prepare je nepovinné, ale je doporučováno.
  5. Voláme Open pro dotazy, které vracejí výsledkovou množinu nebo voláme ExecSQL pro dotazy nevracející výsledkovou množinu.
Po prvním provedení dotazu, pokud nemodifikujeme příkaz SQL, aplikace může opakovaně uzavírat a opětovně otevírat nebo opakovaně spouštět dotaz bez opětovné přípravy.

Specifikování příkazu SQL k provedení

Vlastnost SQL používáme ke specifikaci příkazu dotazu SQL k provedení. Během návrhu, dotaz je připraven a proveden automaticky, když nastavíme vlastnost Active komponenty dotazu na true. Za běhu, dotaz je připraven voláním Prepare a proveden, když aplikace volá metodu Open nebo ExecSQL komponenty.
Vlastnost SQL je objekt TStrings, což je pole textových řetězců a obsahuje vlastnosti, události a metody, které s nim manipulují. Řetězce v SQL jsou automaticky spojeny k vytvoření příkazu SQL k provedení. Příkaz můžeme poskytnout v jednom nebo mnoha oddělených řetězcích, jak potřebujeme. Jednou z výhod použití řady řetězců je to, že můžeme rozdělit příkaz SQL do logických jednotek (např. vložíme klauzuli WHERE pro příkaz SELECT do svého vlastního řetězce) a tak usnadnit modifikaci a ladění dotazu.
Příkaz SQL může být dotaz, který obsahuje pevně kódovaná jména položek a hodnoty nebo může jít o parametrizovaný dotaz, který obsahuje nahraditelné parametry reprezentující hodnoty položek, které musí být spojeny do příkazu před jeho provedením. Např. následující příkaz je pevně kódovaný:
SELECT * FROM Customer WHERE CustNo = 1231
Pevně kódované příkazy jsou užitečné, když aplikace provádí stejný dotaz při každém spuštění. Při návrhu nebo za běhu můžeme snadno nahradit jeden pevně kódovaný dotaz jiným pevně kódovaným nebo parametrizovaným dotazem podle potřeby. Když vlastnost SQL je měněna, pak dotaz je automaticky uzavřen a uvolněn.
Poznámka: V dotazech používajících Lokální SQL, když jména sloupců v dotazu obsahují mezery nebo speciální znaky, pak jméno sloupce musí být uzavřeno v uvozovkách a musí být předcházeno odkazem na tabulku a tečkou. Např. BIOLIFE."Species Name".
Parametrizovaný dotaz obsahuje jeden nebo více míst pro parametry, aplikační proměnné které slouží pro porovnávání hodnot v klauzulích WHERE příkazu SELECT. Používání parametrizovaných dotazů umožňuje změnit hodnotu bez nutnosti přepsání aplikace. Hodnoty parametrů musí být svázané s příkazem SQL před prvním provedením příkazu. Komponenta dotazu toto provede automaticky i když nevoláme metodu Prepare před provedením příkazu.
Tento příkaz je parametrizovaný dotaz:
SELECT * FROM Customer WHERE CustNo = :Number
Proměnná Number (začínající dvojtečkou) je parametr jehož hodnota pro porovnávání musí být poskytnuta za běhu a při každém provádění příkazu může být jiná. Aktuální hodnota pro Number je poskytována ve vlastnosti Params komponenty dotazu.
Tip: Je vhodnou programovací zásadou k poskytování jmen proměnných pro parametry, které odpovídají aktuálnímu jménu sloupce se kterým jsou přiřazeny. Např. pokud jméno sloupce je Number, pak jeho odpovídající parametr bude :Number. Používání shodujících se jmen zajistíme, že když dotaz použije svou vlastnost DataSource k poskytnutí hodnot pro parametry pak můžeme přiřadit jméno proměnné k přípustnému jménu položky.
V této sekci nalezneme ještě tyto body:
Specifikování vlastnosti SQL při návrhu
Vlastnost SQL můžeme specifikovat při návrhu pomocí Editoru seznamu řetězců. K vyvolání Editoru seznamu řetězců pro vlastnost SQL: Příkaz SQL můžeme zadávat na několika řádcích. To usnadňuje jeho čtení, změny a ladění. Stiskem OK přiřadíme zapsaný text vlastnosti SQL. Normálně vlastnost SQL může obsahovat pouze jeden kompletní příkaz SQL, i když tyto příkazy mohou být složité (např. příkaz SELECT s klauzulí WHERE, která používá několik vnořených logických operátorů jako je AND a OR). Některé servery také podporují "dávkovou" syntaxi která umožňuje více příkazů; pokud náš server tuto syntaxi podporuje, pak do vlastnosti SQL můžeme zadat více příkazů.
Poznámka: V některých verzích C++ Builderu, můžeme také použít SQL Builder k vytváření dotazu na základě viditelné reprezentace tabulek a položek v databázi. K použití SQL Builderu, vybereme komponentu dotazu, vyvoláme její místní nabídku a zvolíme Graphical Query Editor. Tato volba je dostupná pouze v některých verzích C++ Builderu.
Specifikování příkazu SQL za běhu
Jsou tři možnosti jak nastavit vlastnost SQL za běhu. Aplikace může nastavit vlastnost SQL přímo, může volat metodu LoadFromFile vlastnosti SQL k zavedení příkazu SQL ze souboru nebo příkaz SQL v seznamu řetězců může být přiřazen vlastnosti SQL.

Přímé nastavování vlastnosti SQL
K přímému nastavení vlastnosti SQL za běhu:

  1. Voláme Close k deaktivaci dotazu. I když pokus o modifikaci vlastnosti SQL automaticky deaktivuje dotaz, je vhodné to provést explicitně.
  2. Pokud nahrazujeme celý příkaz SQL, pak voláme metodu Clear pro vlastnost SQL k zrušení současného příkazu SQL.
  3. Pokud vytváříme celý příkaz SQL z ničeho nebo k existujícímu příkazu přidáváme řádek, pak voláme metodu Add pro vlastnost SQL k přidání jednoho nebo více řetězců k vlastnosti SQL v vytvoření nového příkazu SQL. Můžeme také modifikovat existující řádek vlastnosti SQL s indexem indikujícím ovlivňovaný řádek a přiřazením nové hodnoty.
  4. Voláme Open nebo ExecSQL k provedení dotazu.
Následující kód ukazuje budování celého příkazu SQL z ničeho:
CustomerQuery->Close();      // Uzavření dotazu, je-li aktivní
CustomerQuery->SQL->Clear(); // Zrušení příkazu SQL, je-li
CustomerQuery->SQL->Add("SELECT * FROM Customer");
CustomerQuery->SQL->Add("WHERE Company = 'Sight Diver'");
CustomerQuery->Open();
Poznámka: Pokud dotaz používá parametry, je také nutno nastavit jejich počáteční hodnoty a volat metodu Prepare před otevřením nebo provedením dotazu. Explicitním voláním Prepare je obzvláště užitečné, pokud stejný příkaz SQL je používán opakovaně, jinak je metoda volána automaticky komponentou dotazu.

Zavádění vlastnosti SQL ze souboru
K přiřazení příkazu SQL z textového souboru, můžeme také použít metodu LoadFromFile vlastnosti SQL. Metoda LoadFromFile automaticky vyprazdňuje současný obsah vlastnosti SQL před zavedením nového příkazu ze souboru. Např.
CustomerQuery->Close();
CustomerQuery->SQL->LoadFromFile("C:\\ORDERS.TXT");
CustomerQuery->Open();
Poznámka: Pokud příkaz SQL obsažený v souboru je parametrizovaný příkaz, pak nastavíme počáteční hodnoty pro parametry a voláme metodu Prepare před otevřením nebo provedením dotazu. Explicitním voláním Prepare je obzvláště užitečné, pokud stejný příkaz SQL je používán opakovaně, jinak je metoda volána automaticky komponentou dotazu.

Zavádění vlastnosti SQL z objektu seznamu řetězců
Můžeme také použít metodu Assign vlastnosti SQL ke kopírování obsahu seznamu řetězců do vlastnosti SQL. Metoda Assign automaticky vyprázdní současný obsah před kopírováním nového příkazu.

Nastavování parametrů

Parametrizované příkazy SQL obsahují parametry nebo proměnné, jejichž hodnoty se mohou měnit. Parametry nahrazují datové hodnoty (např. hodnoty použité v klauzuli WHERE po porovnávání), které se vyskytují v příkazu SQL. Parametry normálně slouží pro předávání hodnot příkazu. Např. v následujícím příkazu INSERT vkládané hodnoty jsou předány jako parametry:
INSERT INTO Country (Name, Capital, Population)
VALUES (:Name, :Capital, :Population)
V tomto příkazu SQL, :name, :capital a :population jsou místa pro hodnoty aktuálních parametrů předaných příkazu za běhu aplikací. Dříve než parametrizovaný dotaz může být poprvé proveden, naše aplikace musí volat metodu Prepare ke spojení současných hodnot parametrů s příkazem SQL. Spojení znamená, že BDE a server alokuje zdroje pro příkaz a jeho parametry pro zvýšení rychlosti provádění dotazu.
V této sekci ještě nalezneme:
Dodávání parametrů při návrhu
Při návrhu, parametry v příkazu SQL se zobrazují v Editoru parametrů. K zpřístupnění objektů TParams pro parametry, vyvoláme Editor parametrů, vybereme parametr a přistupujeme k vlastnostem TParam v Inspektoru objektů. Pokud příkaz SQL neobsahuje žádné parametry, pak v Editoru parametrů není uveden žádný objekt TParam. Můžeme pouze přidávat parametry zápisem v příkazu SQL.
K zpřístupnění parametrů:
  1. Vybereme komponentu dotazu.
  2. Stiskneme tlačítko se třemi tečkami pro vlastnost Params v Inspektoru objektů.
  3. V Editoru parametrů vybereme parametr.
  4. Objekt TParam pro vybraný parametr je zobrazen v Inspektoru objektů.
  5. Prohlédneme a modifikujeme vlastnosti pro TParam v Inspektoru objektů.
Pro dotazy, které neobsahují parametry (vlastnost SQL je prázdná nebo existující příkaz SQL nemá parametry), mají seznam parametrů v Editoru parametrů prázdný. Pokud v příkazu SQL jsou použity parametry, pak Editor parametrů uvádí všechny existující parametry.
Poznámka: Komponenta TQuery sdílí objekt TParam a jeho Editor s několika různými komponentami. Místní nabídka Editoru vždy obsahuje volby Add a Delete, které pro komponentu TQuery nemají nikdy význam. Jedinou možností přidávání nebo rušení parametrů TQuery je samotný příkaz SQL.
Když v Editoru parametrů je vybrán parametr, pak Inspektor objektů zobrazuje vlastnosti a události pro tento parametr. Hodnoty vlastností parametrů tedy nastavujeme v Inspektoru objektů.
Vlastnost DataType uvádí datové typy BDE pro parametr vybraný v Editoru. Původní typ je ftUnknown. Pro každý parametr musíme nastavit datový typ. Obecně datové typy BDE jsou přizpůsobené na datové typy serveru.
Vlastnost ParamType uvádí typ parametru vybraného v Editoru. Původní typ je ptUnknown. Typ musíme nastavit pro každý parametr.
Vlastnost Value použijeme ke specifikaci hodnoty pro vybraný parametr při návrhu. Toto není nutné, když hodnotu parametru dodáváme za běhu. V těchto případech ponecháme Value prázdné.
Dodávání parametrů za běhu
K vytvoření parametrů za běhu, můžeme použít: Pro všechny následující příkazy, předpokládáme, že vlastnost SQL obsahuje následující příkaz SQL. Všechny tři použité parametry jsou datového typu ftString.
INSERT INTO "COUNTRY.DB"
(Name, Capital, Continent)
VALUES (:Name, :Capital, :Continent)
Následující kód používá ParamByName k přiřazení textu z editačního ovladače parametru Capital:
Query1->ParamByName("Capital")->AsString = Edit1->Text;
To samé je provedeno pomocí vlastnosti Params, použitím indexu 1 (parametr Capital je druhým parametrem příkazu SQL):
Query1->Params->Items[1]->AsString = Edit1->Text;
Používání datového zdroje ke spojení parametrů
Pokud hodnoty parametrů pro parametrizovaný dotaz nejsou spojeny při návrhu nebo specifikovány za běhu, pak komponenta dotazu se pokusí získat hodnoty na základě své vlastnosti DataSource. DataSource specifikuje jinou komponentu dotazu nebo tabulky, ve které komponenta dotazu může nalézt jména položek odpovídající jménům zatím nespojených parametrů. Tedy prohledávaná datová množina musí být vytvořena a zaplněna před vytvořením komponenty dotazu, která ji používá. Pokud položka je nalezena, pak komponenta dotazu spojuje hodnotu parametru s hodnotou položky v současném záznamu na který ukazuje datový zdroj.
Vytvoříme jednoduchou aplikaci, abychom pochopili jak použít vlastnost DataSource k spojení dotazu do tvaru Master-detail. Předpokládejme, že datový modul pro tuto aplikaci je nazván LinkModule a že obsahuje komponentu dotazu nazvanou OrdersQuery, která má následující vlastnost SQL:
SELECT CustNo, OrderNo, SaleDate
FROM Orders
WHERE CustNo = :CustNo
Datový modul LinkModule také obsahuje: Předpokládejme také, že tato aplikace má formulář nazvaný LinkedQuery, který obsahuje dvě datové mřížky (mřížku Customer Table spojenou s CustomersSource a mřížku Order Query spojenou s OrdersSource).
Následující obrázek ukazuje jak aplikace vypadá při návrhu.


Poznámka: Pokud budeme vytvářet tuto aplikaci, pak musíme vytvořit komponentu tabulky a její datový zdroj před vytvořením komponenty dotazu.
Pokud přeložíme a spustíme tuto aplikaci, pak jelikož parametr v příkazu SQL :CustNo pro OrdersQuery nemá přiřazenou hodnotu, OrdersQuery se pokouší nalézt stejné jméno sloupce v tabulce určené CustomersSource. CustomersSource získává svoje data z CustomersTable, která odvozuje data od tabulky CUSTOMER.DB. Protože CUSTOMER.DB obsahuje sloupec nazvaný CustNo, je hodnota z položky CustNo současného záznamu datové množiny CustomersTable přiřazena parametru :CustNo pro příkaz SQL OrdersQuery. Obě mřížky jsou sestaveny do vztahu Master-detail. Za běhu, pokaždé, když vybereme jiný záznam v mřížce Customer Table, příkaz SELECT OrdersQuery je proveden k získání všech objednávek pro právě vybraného zákazníka.

Provádění dotazu

Po specifikaci příkazu SQL ve vlastnosti SQL a nastavení potřebných parametru pro dotaz, můžeme dotaz provést. Při provádění dotazu BDE získá a zpracovává příkaz SQL od naší aplikace. Pokud dotaz se týká lokálních tabulek (dBASE nebo Paradox), pak SQL BDE zpracovává příkaz SQL a pro příkaz SELECT vrací data aplikaci. Pokud dotaz se vztahuje k tabulce SQL serveru a vlastnost RequiestLive dotazu je nastavena na false, pak příkaz SQL není zpracován nebo interpretován BDE, ale je předán přímo databázovému systému. Když vlastnost RequestLive je nastavena na true, pak příkaz SQL se chová jako standard lokálního SQL a BDE je použito pro převod datových změn na tabulku.
Poznámka: Dříve než můžeme provést dotaz poprvé, musíme volat metodu Prepare k zvýšení výkonnosti dotazu. Prepare inicializuje BDE a databázový server a alokuje pro doraz potřebné systémové zdroje.
V následujících bodech jsou popisovány jak statické tak i dynamické příkazy SQL. Jsou zde tyto body:
Provádění dotazu při návrhu
K provedení dotazu při návrhu, nastavíme jeho vlastnost Active na true v Inspektoru objektů. Výsledek dotazu (je-li nějaký) je zobrazen v datových ovladačích přiřazených ke komponentě dotazu.
Poznámka: Vlastnost Active může být použita pouze s dotazem vracejícím výsledkovou množinu, jako je příkaz SELECT.
Provádění dotazu za běhu
K provedení dotazu za běhu, použijeme jednu z následujících metod: Poznámka: Pokud během návrhu nevíme zda dotaz bude za běhu vracet výsledkovou množinu, pak zakódujeme oba typy provádění dotazu do bloku try ... catch. Volání metody Open vložíme do klauzule try. To umožní potlačit chybové hlášení, které je případně vyvoláno použitím neaplikovatelné metody aktivace pro použitý příkaz SQL. Testujeme tak vzniklé výjimky. Jedná-li se o jinou než ENoResult, pak výjimka byla způsobena z jiného důvodu a musí být zpracována. Toto pracuje, protože akce dotazu bude provedena při aktivování dotazu metodou Open, ale výjimka nastane při použití jiného příkazu SQL než dotazu.

Provádění dotazu vracejícího výsledkovou množinu
K provedení dotazu, který vrací výsledkovou množinu (dotaz, který používá příkaz SELECT), provedeme tyto kroky:

  1. Voláme Close k zajištění toho, aby dotaz již opravdu nebyl otevřen. Pokud dotaz je otevřen, pak jej nemůžeme otevřít znova bez jeho uzavření. Uzavřením dotazu a opětovným otevřením získáme novou verzi dat ze serveru.
  2. Voláme Open k provedení dotazu.
Např.
CustomerQuery->Close();
CustomerQuery->Open(); // Návrat výsledkové množiny

Provádění dotazu bez výsledkové množiny
K provedení dotazu, který nevrací výsledkovou množinu (dotaz, který má příkaz typu INSERT, UPDATE nebo DELETE), voláme k provedení dotazu ExecSQL. Např.
CustomerQuery->ExecSQL(); // Nevrací výsledkovou množinu

Příprava dotazu

Příprava dotazu je nepovinný krok, který předchází provedení dotazu. Příprava dotazu předává příkaz SQL a jeho parametry (jsou-li nějaké), BDE k rozložení, alokování zdrojů a optimalizaci. BDE seznamuje databázový server s přípravou dotazu. Server také pro dotaz může alokovat zdroje. Tyto operce zvyšují výkonnost dotazu, zrychlují naší aplikaci obzvláště při práci s modifikovatelnými dotazy.
Aplikace může připravit dotaz voláním metody Prepare. Pokud nepřipravíme dotaz před jeho provedením, pak jej C++ Builder připraví automaticky při volání Open nebo ExecSQL. I když C++ Builder připraví dotaz za nás, je vhodné provádět explicitní přípravu dotazu. Náš kód je tak srozumitelnější. Např.
CustomerQuery->Close();
if (!CustomerQuery->Prepared)
  CustomerQuery->Prepare();
CustomerQuery->Open();
Tento příklad testuje vlastnost Prepared komponenty dotazu k zjištění zda dotaz je již připraven. Prepared je logická hodnota, která je true, pokud dotaz je již připraven. Pokud dotaz není připraven, pak příklad volá metodu Prepare před voláním Open.

Zrušení připraveného dotazu k uvolnění zdrojů

Metoda UnPrepared nastavuje vlastnost Prepared na false. UnPrepare: K zrušení přípravy dotazu voláme
CustomerQuery->UnPrepare();
Poznámka: Když změníme text vlastnosti SQL pro dotaz, pak komponenta dotazu automaticky uzavře a zruší přípravu dotazu.

Vytváření heterogenních dotazů

C++ Builder podporuje heterogenní dotazy, tj. dotazy na tabulkách ve více než jedné databázi. Heterogenní dotaz může spojovat tabulky na různých serverech a na různých typech serverů. Např. heterogenní dotaz může požadovat tabulku z databáze Oracle, tabulku z databáze Sybase a lokální tabulku dBASE. Když provádíme heterogenní dotaz, pak BDE rozloží a zpracovává dotaz pomocí lokálního SQL. Protože BDE používá lokální SQL, rozšíření SQL specifická pro servery nejsou podporována.
K provedení heterogenního dotazu uděláme tyto kroky:
  1. Definujeme samostatné přezdívky BDE pro každou databázi použitou v dotazu. Vyprázdníme vlastnost DatabaseName TQuery; jména dvou použitých databází specifikujeme v příkazu SQL.
  2. Specifikujeme příkaz SQL k provedení ve vlastnosti SQL. Každé jméno tabulky v příkazu SQL musí předcházet přezdívka pro databázi, ve které tabulku můžeme nalézt. Přezdívky BDE předcházející jméno tabulky uzavřeme do dvojteček. Celý odkaz na tabulku pak uzavřeme do uvozovek.
  3. Nastavíme potřebné parametry pro dotaz do vlastnosti Params.
  4. Voláme Prepare pro přípravu dotazu na provedení před prvním provedením.
  5. Voláme Open nebo ExecSQL v závislosti na typu prováděného dotazu.
Např. předpokládejme, že jsme definovali přezdívku nazvanou Oracle1 pro databázi Oracle s tabulkou CUSTOMER a přezdívku Sybase1 pro databázi Sybase s tabulkou ORDERS. Jednoduchý dotaz spojující tyto dvě tabulky bude:
SELECT Customer.CustNo, Orders.OrderNo
FROM ":Oracle1:CUSTOMER"
  JOIN ":Sybase1:ORDERS"
    ON (Customer.CustNo = Orders.CustNo)
WHERE (Customer.CustNo = 1503)
Jako alternativa k používání přezdívky BDE ke specifikaci databáze v heterogenním dotazu, můžeme použít komponentu TDatabase. Konfigurujeme TDatabase jako normálně k ukazování na databázi, nastavíme TDatabase::DatabaseName na libovolnou, ale unikátní hodnotu a potom použijeme tuto hodnotu v příkazu SQL namísto jména přezdívky BDE.

Zvyšování výkonnosti dotazu

Následují kroky, které můžeme provést k zvýšení rychlosti provádění dotazu: Vlastnost UniDirectional určuje zda pro dotaz jsou povoleny obousměrné kurzory BDE. Když dotaz vrátí výsledkovou množinu, je také získán kurzor (ukazatel na první záznam ve výsledkové množině). Záznam určený kurzorem je současný aktivní záznam. Současný záznam je ten, jehož hodnoty položek jsou zobrazeny v datových ovladačích přiřazených k datovému zdroji výsledkové množiny.
UniDirectional je implicitně false, což znamená, že kurzor pro výsledkovou množinu může procházet po záznamech dopředu i dozadu. Obousměrné kurzory vyžadují určité zpracování, což může zpomalit některé dotazy. Pro zvýšení výkonnosti dotazu, můžeme natavit UniDirectional na false k omezení zpětného pohybu kurzoru ve výsledkové množině.
Pokud nepotřebujeme procházet výsledkovou množinou zpět, pak můžeme nastavit UniDirectional na true pro dotaz. UniDirectional nastavíme před přípravou a provedením dotazu. Následující kód ukazuje nastavení UniDirectional před přípravou a provedením dotazu:
if (!CustomerQuery->Prepared)
{
  CustomerQuery->UniDirectional = true;
  CustomerQuery->Prepare();
}
CustomerQuery->Open(); // Vrací výsledkovou množinu s jednosměrným kurzorem

Práce s výsledkovou množinou

Implicitně výsledková množina vracená dotazem je určená pouze pro čtení. Naše aplikace může zobrazovat hodnoty položek z výsledkové množiny v datových ovladačích, ale uživatel tyto hodnoty nemůže editovat. K umožnění editování výsledkové množiny, naše aplikace musí požadovat "živou" výsledkovou množinu.
V této sekci jsou uvedeny tyto body:
Povolení editace výsledkové množiny
K získání výsledkové množiny, kde uživatel může editovat datové ovladače, nastavíme vlastnost RequestLive komponenty dotazu na true. Nastavením RequestLive na true ješte nezajistíme živou výsledkovou množinu, ale BDE se ji pokusí zajisti, pokud je to množné. Jsou některá omezení na živou výsledkovou množinu, závisející na tom zda dotaz používá lokální SQL nebo serverové SQL. Heterogenní dotazy prováděné na tabulkách Paradoxu nebo dBASE jsou předány BDE pomocí lokálního SQL. Dotazy určené vzdálenému databázovému serveru jsou předány serveru.
Pokud aplikace požaduje a získá živou výsledkovou množinu, pak vlastnost CanModify komponenty dotazu je nastavena na true. Pokud aplikace požaduje živou výsledkovou množinu, ale syntaxe příkazu SELECT to neumožňuje, pak BDE vrací:
Požadavky lokálního SQL na živou výsledkovou množinu
Pro dotazy, které používají lokální SQL, BDE nabízí rozšířenou podporu pro aktualizování živé výsledkové množiny v jednoduché tabulce i ve více tabulkovém dotazu. Lokální SQL je použito, když dotaz je proveden na jedné nebo více tabulkách dBASE nebo Paradoxu, nebo na jedné nebo více tabulkách vzdáleného serveru, když tato jména v dotazu jsou předcházena BDE přezdívkou databáze.
Pro dotaz na jednoduché tabulce nebo pohledu je vrácena živá výsledková množina, pokud dotaz neobsahuje nic z následujícího:
Požadavky vzdáleného serveru pro živou výsledkovou množinu
Pro dotazy používající průchozí SQL (celý dotaz je předán vzdálenému serveru), živé výsledkové množiny jsou omezeny na standard definovaný SQL-92 a další serverová omezení. Živá výsledková množina pro dotaz na samostatné tabulce nebo pohledu je vrácena, pokud dotaz neobsahuje nic z následujícího:
Omezení na aktualizacích živé výsledkové množiny
Pokud dotaz vrací živou výsledkovou množinu, pak výsledková množina nemusí být aktualizovatelná přímo, pokud výsledková množina obsahuje spojované položky nebo přepneme indexy před pokusem o aktualizaci. Pokud tyto omezení existují, pak výsledkovou množinu můžeme chápat jako množinu určenou pouze pro čtení.
Aktualizování výsledkové množiny určené pouze pro čtení
Aplikace může aktualizovat data vracená výsledkovou množinou určenou pouze pro čtení, pokud používáme odložené aktualizace. K aktualizaci výsledkové množiny určené pouze pro čtení přiřazené ke komponentě dotazu:
  1. Přidáme komponentu TUpdateSQL k datovému modulu v naši aplikaci k umožnění odesílat aktualizace do datové množiny určené pouze pro čtení.
  2. Zadáme příkaz aktualizace SQL pro výsledkovou množinu k vlastnostem ModifySQL, InsertSQL nebo DeleteSQL komponenty.
  3. Nastavíme vlastnost CachedUpdate komponenty dotazu na true.

  1. V adresáři Program files\Borland\CBuilder\Examples\DBTask\Filter nalezneme demonstrační aplikaci filtrující záznamy databáze. Jsou zde také přepínány datové množiny. Prohlédněte si tuto aplikaci a zjistěte jak pracuje.
  2. V adresáři Program files\Borland\CBuilder\Examples\DBTask\Contacts spravující zákazníky a jejich objednávky. Prohlédněte si také tuto aplikaci a zjistěte jak pracuje.
17. Práce s dotazy