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:
-
SQL a naší serverovou implementací SQL, včetně omezení a
rozšíření standardu SQL-92.
-
BDE (Borland Database Engine).
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:
-
K více než jedné tabulce (spojení v SQL).
-
Specifikací podmnožiny řádků a sloupců ve svých tabulkách,
místo návratu všech řádků a sloupců. To zvyšuje výkonnost i bezpečnost.
Nejsou požadována nepotřebná data a zabraňujeme v přístupu k položkám,
které nebudeme prohlížet nebo modifikovat.
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:
-
Tabulkám Paradoxu nebo dBASE pomocí Lokálního SQL, které
je částí BDE. Lokální SQL je podmnožina specifikace SQL-92. Je podporována
většina DML a některá syntaxe DDL pro práci s těmito typy tabulek.
-
Databázovým serverem Lokální InterBase, pomocí modulu přístupu
k databázi InterBase.
-
Databáze na vzdálených databázových serverech jako je Oracle,
Sybase, MS-SQL Server, Informix, DB2 a InterBase (v závislosti na verzi
C++ Builder). Musíme mít instalován příslušný ovladač SQL Server a klientský
software závisející na databázovém serveru pro přístup na vzdálený server.
Všechna standardní syntaxe SQL podporovaná těmito servery je povolena.
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:
-
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.
-
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.
-
Ve vlastnosti SQL komponenty specifikujeme příkaz
SQL a nepovinně specifikujeme libovolné parametry pro příkaz ve vlastnosti
Params.
-
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.
-
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:
-
Komponentu dotazu uzavřeme.
-
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.
-
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.
-
Voláme Prepare k inicializaci BDE a spojení hodnoty
parametrů v dotazu. Volání Prepare je nepovinné, ale je doporučováno.
-
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:
-
Dvojitě klikneme ve sloupci hodnot vlastnosti SQL
nebo
-
Stiskneme zde tlačítko s třemi tečkami.
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:
-
Voláme Close k deaktivaci dotazu. I když pokus o modifikaci
vlastnosti
SQL automaticky deaktivuje dotaz, je vhodné to provést
explicitně.
-
Pokud nahrazujeme celý příkaz SQL, pak voláme metodu Clear
pro vlastnost
SQL k zrušení současného příkazu SQL.
-
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.
-
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ů:
-
Vybereme komponentu dotazu.
-
Stiskneme tlačítko se třemi tečkami pro vlastnost Params
v Inspektoru objektů.
-
V Editoru parametrů vybereme parametr.
-
Objekt TParam pro vybraný parametr je zobrazen v Inspektoru
objektů.
-
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:
-
Metodu ParamByName k přiřazení hodnot parametrům na
základě jejích jmen.
-
Vlastnost Params k přiřazení hodnot parametrům na
základě pořadí parametru v příkazu SQL.
-
Vlastnost Params->ParamValues k přiřazení jednoho
nebo více parametrů v jednom příkazovém řádku na základě jména množiny
parametrů. Tato metoda používá varianty a nepožaduje přetypování hodnot.
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:
-
Komponentu TTable nazvanou CustomersTable spojenou
s tabulkou CUSTOMER.DB.
-
Komponentu TDataSource nazvanou OrdersSource.
Vlatnost DataSet ukazuje na OrdersQuery.
-
TDataSource nazvanou CustomersSource spojenou
s CustomersTable. Vlastnost DataSource komponenty OrdersQuery
je také nastavena na CustomersSource. Toto nastavení dělá OrdersQuery
sestaveným dotazem.
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:
-
Open provádí dotaz, který vrací výsledkovou množinu
(příkaz SELECT).
-
ExecSQL provádí dotaz, který nevrací výsledkovou množinu
(příkazy INSERT, UPDATE nebo DELETE).
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:
-
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.
-
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:
-
Zajistí, že vlastnost SQL bude před dalším provedeném
opět připravena.
-
Požaduje od BDE uvolnění interních zdrojů alokovaných pro
příkaz
-
Požaduje od serveru uvolnění všech zdrojů, které byly alokovány
pro příkaz.
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:
-
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.
-
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.
-
Nastavíme potřebné parametry pro dotaz do vlastnosti Params.
-
Voláme Prepare pro přípravu dotazu na provedení před
prvním provedením.
-
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:
-
Nastavíme vlastnost UniDirectional dotazu na true,
pokud výsledkovou množinou nebudeme potřebovat procházet nazpět. Implicitně
UniDirectional
je false, protože BDE podporuje implicitně obousměrné dotazy.
-
Připravíme dotaz před provedením. To je obzvláště užitečné,
když plánujeme provedení jednoduchého dotazu několikrát. Je nutno připravit
dotaz pouze jednou a to před jeho prvním použitím.
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í:
-
výsledkovou množinu určenou pouze pro čtení pro dotazy na
Paradoxu nebo dBASE
-
chybový kód pro SQL předané na vzdálený server.
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:
-
DISTINCT v klauzuli SELECT
-
Spojení (vnitřní, vnější nebo UNION)
-
Agregační funkce (s nebo bez klauzulí GROUP BY nebo HAVING)
-
Základní tabulky nebo pohledy, které nejsou aktualizovatelné
-
Poddotazy
-
Klauzuli ORDER BY nezaloženou na indexech
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:
-
Klauzuli DISTINCT v příkazu SELECT
-
Agregační funkce (s nebo bez klauzulí GROUP BY nebo HAVING)
-
Odkazy na více než jednu základní tabulku nebo aktualizovatelný
pohled
-
Poddotazy, které se odkazují na tabulky v klauzuli FROM nebo
ostatní tabulky
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:
-
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í.
-
Zadáme příkaz aktualizace SQL pro výsledkovou množinu k vlastnostem
ModifySQL,
InsertSQL
nebo DeleteSQL komponenty.
-
Nastavíme vlastnost CachedUpdate komponenty dotazu
na true.
-
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.
-
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.