18 rozdzial 17 UXCTXEQZKIEB67R3 Nieznany (2)

background image

Rozdział 17

Delphi a Interbase

W tym rozdziale przedstawimy Interbase RDBMS. Omówimy elementy SQL oraz
niektóre zagadnienia dotyczące wspólnej pracy InterBase i Delphi. Opiszemy także
podstawy administrowania serwerami InterBase.

Zaczniemy oczywiście od uruchomienia serwera.

Uruchamianie serwera InterBase

Sposób uruchomienia serwera w dużym stopniu zależy od systemu operacyjnego.
Mając na uwadze fakt, że nie jest to książka poświęcona wyłącznie systemowi
InterBase, ograniczymy nasze rozważania tylko do najpopularniejszych - Windows
95 i Windows NT.

Po przeprowadzeniu standardowej instalacji, serwer InterBase uruchamia się
automatycznie przy każdym starcie Windows. Na pasku zadań w Windows 95/NT
pojawia się wtedy jego ikona ( lub ikona na pulpicie, jeśli używamy Windows NT
3.51 ).

Klikając ikonę na pasku zadań prawym przyciskiem myszy, uzyskujemy dostęp do
podstawowych ustawień serwera. Jeśli np. wybierzemy - z menu rozwijalnego -
pozycję

Startup Configuration

, serwer będzie startował równolegle z Windows. Po

wybraniu z kolei

Properties

, będziemy mogli odczytać dopuszczalną i aktualną

liczbę połączeń z serwerem.

Łączenie się z serwerem

W przeciwieństwie do omówionych dotychczas serwerów - aby uzyskać dostęp do
serwerów InterBase, nie musimy definiować oddzielnego połączenia. Jeśli
korzystamy z lokalnego serwera InterBase, oprogramowanie klienta (WISQL,
BDE, itp. ) odwołuje się bezpośrednio do pliku bazy danych (nie ma potrzeby
podawania jakichkolwiek danych odnoszących się do serwera).

W przypadku odległego serwera (InterBase), niezbędne do połączenia informacje
zależą od wyboru protokołu sieciowego. Jeśli łączymy się poprzez TCP/IP, wtedy
plik HOSTS musi zawierać dane dotyczące naszego serwera, np.:

100.10.15.12 marketing

background image

506

Część III

Także plik TCP SERVICES powinien zostać uzupełniony o linię definiującą
protokół dostępu InterBase:

gds_db 3050/tcp

Oczywiście odpowiednie zmiany w

plikach dokonywane są automatycznie

w czasie instalacji serwera. Gdy tylko skonfigurujemy dostęp poprzez TCP/IP,
możemy korzystać z WISQL i innych narzędzi InterBase. Należy jeszcze raz
podkreślić, że podane wymagania dotyczące plików inicjacyjnych odnoszą się
tylko do TCP/IP. NetBEUI ani IPX/SPX nie nakładają tego typu wymagań.

Konfigurowanie Aliasów BDE

Teraz utworzymy alias BDE, który umożliwi aplikacjom w Delphi dostęp do
serwera. Ten temat był już omawiany wcześniej, dlatego teraz przedstawimy tylko
kolejne kroki, które pozwolą poprawnie go skonfigurować.

Chcąc zbudować alias BDE powinniśmy wybrać jedno z

narzędzi: BDE

Administrator lub Delphi Database Explorer. Opisany poniżej sposób
postępowania odnosi się do programu BDE Administrator.

1. Uruchamiamy BDE Administrator, klikamy prawym przyciskiem myszy fiszkę

Databases

i wybieramy

New

. W oknie dialogowym

New Database Alias

wybieramy, z listy typów aliasów,

INTRBASE

i klikamy

OK

.

2. Wpisujemy nazwę nadaną tworzonemu aliasowi .

3. Konfigurujemy go przez odpowiednie ustawienie parametrów na stronie

Definition

4. Klikamy parametr

SERVER NAME

i wprowadzamy nazwę serwera oraz plik

bazy danych, z którym chcemy się łączyć. Przyjęto konwencję, że ten plik ma
rozszerzenie

GDB

. Wprowadzane dane powinny przyjmować postać:

MIS:/data/interbase/accounting.gdb

gdzie

MIS

jest nazwą twojego serwera a

/data/interbase/

accounting.gdb

jest pełną ścieżką do pliku zawierającego bazę danych.

WSKAZÓWKA

Jeśli korzystamy z lokalnego serwera InterBase, pole

SERVER NAME

może

pozostać niewypełnione. Wystarczy podać tylko pełną ścieżkę dostępu do pliku
zawierającego bazę danych., np.

C:\DATA\INTERBASE\ACCOUNT.GDB

background image

Rozdział 17 Delphi w Interbase

507

5. Jeśli podamy nazwę użytkownika (parametr

USER NAME

), to będzie on

domyślnie przyłączany do serwera. Podana nazwa będzie też umieszczana we
wbudowanym w Delphi oknie dialogowym logowania.

Jak widać jest kilka innych parametrów, którym możemy nadać odpowiednie
wartości. W szczególności jeden z nich powinien być zawsze ustawiony dla
aliasów InterBase -

ENABLE BCD. D

ecyduje on bowiem o tym, jak BDE będzie

interpretował pewne typy danych numerycznych. Chociaż paramatr ma w swej
nazwie BCD, to jednak jego zasięg nie ogranicza się tylko do danych BCD
(Binary-Coded Decimal), ale dotyczy także typów zmiennoprzecinkowych:
DECIMAL i

NUMERIC. Gdy

ENABLE BCD

jest ustawiony na

FALSE

(ustawienie domyślne), pola DECIMAL lub NUMERIC będą traktowane przez
Delphi jako integers (całkowite). W konsekwencji elementy rozpoznające rodzaj
danych uniemożliwią nam wprowadzanie części dziesiętnych liczb. Dlatego
powinniśmy ustawiać

ENABLE BCD

na

TRUE

we wszystkich aliasach.

Po wybraniu

Apply

wprowadzone zmiany zostają zapamiętane.

Rozwiązywanie problemów połączeniowych z serwerem InterBase

Poniżej zebraliśmy kilka praktycznych porad, które mogą okazać się przydatne
w

przypadku napotkania problemów połączeniowych w naszych aplikacjach

w Delphi.

1. Skorzystamy najpierw z

narzędzia Interbase Communication Diagnostic,

umieszczonego w folderze InterBase 4.2. Klikamy przycisk

Test

ze strony

DB

Connection

. Brak połączenia może być spowodowany złą konfiguracją aliasu

BDE. W takiej sytuacji powinniśmy powrócić do programu BDE Administrator
i upewnić się, czy podane ustawienia są poprawne. Jeśli nadal nie będziemy
uzyskiwali połączenia z DB Connection, powinniśmy przejść na stronę

NetBEUI

lub

Winsock

( wybierając odpowiednią fiszkę) i kliknąć

Test

. Jeśli

choć jeden będzie funkcjonował poprawnie, to prawdopodobną przyczyną
braku połączenia są złe ustawienia parametrów. Jeśli żadna z prób się nie
powiedzie (a mamy pewność, że serwer jest uruchomiony), proponujemy
kontynuowanie diagnostyki według zamieszczonego poniżej opisu.

2. Jeśli InterBase WISQL umożliwia nawiązanie komunikacji z serwerem,

natomiast nadal występują problemy połączeniowe w naszej aplikacji, to
prawdopodobnie konfiguracja aliasu DBE jest niewłaściwa. W takiej sytuacji
powinniśmy powrócić do programu BDE Administrator i upewnić się, czy
podane ustawienia są poprawne ( w szczególności nazwa serwera).

3. Brak połączenia poprzez WISQL świadczy o wadliwym funkcjonowaniu

protokołu sieciowego. Jeśli korzystamy z TCP/IP, łączność z serwerem można
sprawdzić za pomocą programu PING, który jest dostarczany z Windows 95 /

background image

508

Część III

NT. Powinniśmy spróbować łączenia poprzez nazwę komputera zapisaną
w pliku HOSTS lub poprzez jego adres IP.

4. Jeśli korzystamy z nazwanych potoków (ang. named pipes) - do komunikacji

z serwerem pracującym w Windows NT powinniśmy użyć polecenia

net

view \\ servername

, gdzie

servername

jest nazwą komputera w sieci

NT, na którym funkcjonuje serwer SQL. Po poprawnej realizacji

net view

posłużymy się instrukcją

netuse \\servername\IPC$,

zamieniając

servername

na nazwę naszego serwera. Wystąpienie jakichkolwiek

nieprawidłowości wskazuje na brak połączenia z komputerem serwera w sieci.
W takim przypadku proponujemy zwrócić się do administratora systemu NT.
Źródłem zakłóceń może być też wadliwa obsługa potoków na serwerze.

5. W sytuacji, gdy uzyskaliśmy połączenie poprzez adres IP, co nie powiodło się

za pośrednictwem nazwy serwera, powinniśmy dokładnie sprawdzić dane
w pliku

HOSTS

, bowiem oprogramowanie klienta InterBase’a korzysta z niego

przy wyszukiwaniu serwera. W pliku

HOSTS

musi się znaleźć odpowiednia

linia z informacjami o każdym serwerze, z którym chcemy się połączyć np:

100.10.15.12 marketing

6. Gdy nie udało się nam połączyć z serwerem (ani poprzez nazwę ani adres IP),

to prawdopodobną przyczyną może być uszkodzenie sieci. Oczywiście
powinniśmy jeszcze raz sprawdzić adres IP serwera oraz uruchomić

PING

(podając adres

127.0.0.1

) - aby przekonać się, czy stos protokołu TCP/IP

funkcjonuje poprawnie. Jeśli test się nie powiedzie, to prawdopodobnie źle
skonfigurowano sam protokół. W takim przypadku proponujemy zwrócić się do
administratora sieci.

7. Może się też zdarzyć, że nie uzyskujemy połączenia poprzez WISQL, natomiast

PING umożliwia nawiązanie komunikacji. W takim przypadku możemy
skorzystać z Telnetu (dostarczanego wraz z Windows95/NT). Składnia wywołania
wygląda następująco:

TELNET 100.100.100.100

lub

TELNET hostname

gdzie

100.100.100.100

jest adresem TCP/IP komputera serwera a hostname

jego nazwą. Przyczyną braku połączenia poprzez Telnet może być wadliwe
działanie demona inet na serwerze.

8. Jeśli połączyliśmy się poprzez Telnet przy wciąż nie funkcjonującym WISQL,

powinniśmy się upewnić, czy oprogramowanie serwera InterBase’a zostało
poprawnie zainstalowane i uruchomione. Istotne jest także, czy plik

TCP

SERVICES

zawiera niezbędne informacje. Powinny one przyjmować postać:

background image

Rozdział 17 Delphi w Interbase

509

gds_db 3050/tcp

9. Jeśli nasze działania nie przyniosły pożądanego rezultatu, powinniśmy

skonsultować się z administratorem sieci lub bazy danych.

Wstęp do SQL

Język SQL należy do podstawowych środków komunikowania się z serwerami baz
danych. Niniejszy rozdział jest wprowadzeniem do własnej, bogatej odmiany SQL,
wykorzystywanej przez InterBase. Zwrócimy tutaj uwagę na kilka właściwości,
które różnią tę implementację SQL od dostarczanych przez innych sprzedawców.
Aby móc poznawać w praktyce prezentowane elementy języka, wystarczy
zapewnić sobie dostęp do uruchomionego serwera i umieć się z nim komunikować
poprzez WISQL.

Tworzenie bazy danych

Zaczniemy od utworzenia bazy danych i umieszczenia w niej tymczasowych tabel,
które zostaną wykorzystane w podanych dalej przykładach. W tym celu posłużymy
się instrukcją

CREATE DATABASE

. Jej składnia zależy od konkretnej

implementacji SQL. Poniższy przykład przedstawia podstawową składnię
InterBase’a:

CREATE DATABASE "C:\DATA\IB\SALES" USER SYSDBA PASSWORD

masterkey

Aby utworzyć bazę danych używając InterBase WISQL, korzystamy z polecenia

Create

Database

z menu

File

. A oto sposób postępowania:

1. Uruchamiamy program interaktywnej obsługi SQL (WISQL) - albo z grupy

programów InterBase’a albo z paska zadań z InterBase Server Manager.

2. Wybieramy polecenie

Create

Database

z menu

File

.

3. Wpisujemy pełną ścieżkę dostępu do bazy, którą chcemy utworzyć (np.

C:\DATA\IB\SALES.GB

) w

polu

Database

okna dialogowego

Create

Database

.

4. Podajemy nazwę użytkownika i hasło. Domyślne wartości tych parametrów to:

nazwa użytkownika-

SYSDBA

; hasło -

masterkey

.

5. Klikamy przycisk

OK

. InterBase powinien utworzyć bazę danych i podłączyć

nas do niej. Później - do łączenia się z istniejącą bazą - korzystamy z polecenia

Connect to

Database

z menu

File

.

W oknie dialogowym

Create DataBase

,w części

Database Options

, można ustawić

pewne parametry bazy, między innymi rozmiar stron (w bajtach) tworzących bazę.

background image

510

Część III

Domyślnie jest przyjmowane 1024 (1K), a dopuszczalne są jeszcze wartości 2048,
4096 lub 8192 ( np.

PAGE_SIZE=2048

).

Można też określić dodatkowe pliki, które zostaną utworzone wraz
z podstawowym plikiem bazy danych oraz podać dla nich początkowe wielkości.

WSKAZÓWKA

Utworzenie bazy w WISQL jest możliwe tylko przez wybór odpowiedniej pozycji
z menu. Mamy jednak do dyspozycji program ISQL (umieszczany domyślnie
w kartotece

C:\Program Files\Borland\IntrBase\Bin

), umożliwia-

jący wydawanie w linii poleceń instrukcji SQL, dostępnych w WISQL tylko za
pośrednictwem odpowiednich pozycji menu.

Cienie (shadows)

Serwer InterBase pozwala tworzyć specjalny obiekt nazwany cieniem, do
utrzymywania lustrzanego odbicia bazy danych na innym dysku (lub dyskach).
Dzięki temu może być ona nadal dostępna - nawet w przypadku jej uszkodzenia na
podstawowym dysku lub uszkodzenia samego dysku.

Wydanie instrukcji

CREATE SHADOW

spowoduje stworzenie cienia dla aktywnej

bazy danych. Składnia polecenia jest następująca:

CREATE SHADOW 1 "sales.shd" LENGTH 5000

Podajemy unikalny numer cienia jako pierwszy parametr instrukcji. Jeśli numer
zostanie pominięty lub będzie się powtarzał, InterBase nie utworzy cienia.

Dublowanie bazy wiąże się z podwojeniem liczby zapisów, które są wykonywane
w czasie przeprowadzanych zmian. Należy się z tym liczyć przy wyborze
lokalizacji dla cienia. Praca z powolnym dyskiem może istotnie obniżyć wydajność
systemu

Instrukcja

CREATE SHADOW

ma specjalny parametr pozwalający ustalić

zachowanie się systemu, gdy cień będzie niedostępny. Po wybraniu wartości

AUTO

aplikacje klienta będą nadal przyłączone do bazy, a cień zostanie skasowany.
Ustawienie

MANUAL

zablokuje wszystkie połączenia - aż do chwili, gdy cień

będzie ponownie dostępny lub zostanie usunięty (instrukcją

DROP SHADOW).

CONDITIONAL

pozwoli kontynuować połączenia i

spowoduje utworzenie

nowego cienia. Jeśli parametr jest ustawiony na

CONDITIONAL,

wtedy

w przypadku uszkodzenia bazy jej miejsce zajmie cień i jednocześnie zostanie
utworzony cień nowo promowanego cienia. A oto jeszcze jeden przykład:

background image

Rozdział 17 Delphi w Interbase

511

CREATE SHADOW 1 CONDITIONAL "d:\shadows\sales.shd" LENGTH

5000 ;

Oczywiście zastosowane słowo kluczowe

CONDITIONAL

określa zachowanie się

bazy, gdy cień będzie niedostępny.

Instrukcja CONNECT

Instrukcja InterBase SQL - CONNECT - umożliwia łączenie się z istniejącą bazą
danych. Posiada ona następującą składnię:

CONNECT ServerAndDatabasePath USER "ValidUser" PASSWORD

"UserPassword"

ServerAndDatabasePath

oznacza pełną ścieżkę do serwera i bazy danych,

z którą chcemy się połączyć. Jeśli serwer jest uruchomiony lokalnie, wystarczy
podać tylko ścieżkę do bazy danych.

ValidUser

i

UserPassword

to

odpowiednio: nazwa użytkownika i hasło na naszym serwerze bazy danych.
W przypadku lokalnej bazy danych instrukcja

CONNECT

może mieć postać:

CONNECT "C:/DATA/IB/SALES.GDB" USER "SYSDBA" PASSWORD

"masterkey"

Każdorazowo, gdy łączymy się z inną bazą danych, jesteśmy odłączani od
bieżącej.

DISCONNECT

umożliwia zerwanie połączenia (ustalonego wcześniej poleceniem

CONNECT)

. Typowy przykład:

DISCONNECT ALL;

Ten sam efekt osiągniemy zastępując

ALL

. przez

DEFAULT

.W WISQL jesteśmy

zmuszeni do korzystania z poleceń

Connect to DataBase

i

Disconnect

from Database

z menu

File

(

CONNECT

i

DISCONNECT

nie działają bowiem

w WISQL bezpośrednio, ale można ich użyć w linii poleceń w ISQL).

Tworzenie tabel

Gdy jesteśmy już podłączeni do bazy, możemy rozpocząć definiowanie obiektów.
Prawie każde pojęcie odnoszące się do relacyjnych baz danych może być
zaprezentowane za pomocą trzech tabel. Utwórzmy więc na początek trzy tabele,
dzięki którym będziemy mogli zrozumieć istotę omawianych zagadnień.
Posłużymy się poleceniem SQL:

CREATE TABLE

. Wprowadźmy odpowiednią

instrukcję korzystając z programu WISQL, aby utworzyć tabelę CUSTOMER:

background image

512

Część III

CREATE TABLE CUSTOMER
(
CustomerNumber int

NOT

NULL,

LastName Char(30),
FirstName char(30),
StreetAddress char(30),
City char(20),
State char(2),
Zip char(10),
)

Dalej utwórzmy tabelę SALE :

CREATE TABLE SALE
(
SaleNumber int NOT

NULL,

SaleDate date,
CustomerNumber int

NOT

NULL,

ItemNumber int NOT

NULL,

Amount float
)

Po zbudowaniu tabeli SALE, pozostała do utworzenia tylko tablica ITEM:

CREATE TABLE ITEM
(
ItemNumber int

NOT

NULL,

Description char(30),
Price float
)

Tabele zewnętrzne

InterBase wykorzystuje pewne interesujące odmiany instrukcji

CREATE TABLE

.

Jedna z takich alternatywnych postaci umożliwia tworzenie tabel zewnętrznych
w stosunku do bazy, np.:

CREATE TABLE SALE_HISTORY EXTERNAL FILE

C:\DATA\IB\SALEHIST.DAT

(
SaleNumber int

NOT

NULL,

SaleDate date,
CustomerNumber int

NOT

NULL,

ItemNumber int

NOT

NULL,

Amount float
)

Jeśli określony w poleceniu plik zewnętrzny nie istnieje, wtedy InterBase go
utworzy, w przeciwnym wypadku pozostanie nie zmieniony. Dzięki tej instrukcji
można odwoływać się do danych utworzonych poza InterBase - np. tabeli, w której
przechowuje się dane z innego systemu DBMS. Jeśli wyspecyfikowana struktura

background image

Rozdział 17 Delphi w Interbase

513

tabeli w InterBase będzie zgodna ze strukturą danych zewnętrznych, można
skopiować wiersze z pliku zewnętrznego do wewnętrznej tabeli poleceniem:

INSERT...SELECT.

Kolumny obliczane (Computed columns)

Instrukcja

CREATE TABLE

w InterBase umożliwia także definiowanie kolumn

obliczanych. Poniżej przedstawiamy tabelę ITEMS, rozszerzoną o dodatkową
kolumnę obliczaną - GovernmentPrice :

CREATE TABLE ITEM
(
ItemNumber int

NOT

NULL,

Description char(30),
Price float
GovernmentPrice COMPUTED BY (Price-Price* .15)
)

W tym przypadku w kolumnie

GovermentPrice

uwzględniono 15% zniżki (w

stosunku do ceny w kolumnie

PRICE

) dla klientów rządowych. Ponieważ nie

został w niej podany typ danych, Interbase ustala go na podstawie typu z kolumn
wykorzystywanych do obliczeń. Definicje kolumn wykorzystywanych przez
kolumnę obliczaną muszą oczywiście - na liście kolumn polecenia

CREATE

TABLE -

wystąpić przed nią.

Podobne możliwości daje oczywiście instrukcja SELECT czy perspektywa.
Jednak w tym wypadku wpisujemy obliczenia bezpośrednio do definicji tabeli.
Jest to dobry sposób na ustalenie pewnych zależności obliczeniowych. Wtedy
bowiem aplikacje i inne obiekty SQL mogą po prostu pobierać obliczone wartości
z kolumny obliczanej.

Kolumny tablicowe (Array Columns )

W uzupełnieniu prostych typów danych InterBase pozwala na zdefiniowanie
kolumn, które są tablicami danych zadanego typu. Zdefiniowanie kolumny jako
tablicy pozwala traktować naturalnie zgrupowane elementy danych jako zbiór.
Przedstawiamy przykład zmodyfikowanej tabeli CUSTOMER, która zawiera
kolumnę tablicową:

CREATE TABLE CUSTOMERARRAY
(
CustomerNumber int

NOT

NULL,

LastName Char(30),
FirstName char(30),
StreetAddress char(30)[3],
City char(20),

background image

514

Część III

State char(2),
Zip char(10),
)

Należy zwrócić uwagę na oznaczenie "[3]" po prawej stronie w definicji kolumny
StreetAddress. Zgodnie z podanym opisem będzie ona interpretowana jako
trzyelementowa tablica elementów typu char (30). Umożliwia więc zapisanie
poszczególnych części adresu w trzech osobnych liniach.

Oczywiście możemy też podać zakres indeksów tablicy, np.

CREATE TABLE CUSTOMERARRAY
(
CustomerNumber int

NOT

NULL,

LastName Char(30),
FirstName char(30),
StreetAddress char(30)[1:3],
City char(30),
State char(2),
Zip char(10),
)

Także w tym przypadku StreetAddress jest jednowymiarową, trójelementową
tablicą lecz indeksowaną liczbami od 1 do 3, a nie - jak w poprzednim przykładzie
- domyślnie od 0 do 2.

Tablice w kolumnach mogą być także wielowymiarowe ( największy wymiar 16).
Prezentuje to prosty przykład:

CREATE TABLE HOURLY_SAMPLES
(
SampleNo int

NOT

NULL,

SampleDate DATE

NOT

NULL,

WeeklySampleValues int[6,23]
)

Zdefiniowana powyżej kolumna

WeeklySampleValues

jest dwuwymiarową

tablicą, w której można gromadzić dane typu int, odnoszące się do każdej godziny,
przez cały tydzień.

background image

Rozdział 17 Delphi w Interbase

515

OSTRZEŻENIE

Zanim wykorzystamy kolumny tablicowe, w naszych bazach danych warto
przeanalizować pewne konsekwencje implementacyjne. Kolumny tablicowe są
istotnie powtarzającymi się grupami. Mówiąc formalnie naruszają pierwszą postać
normalną. Wymagają także dodatkowego nakładu pracy przy podstawianiu (nie
można podstawić wartości kolumny tablicowej używając SQL), formatowaniu (np.
przy raportach) oraz przy zapytaniach. Jest także wiele ograniczeń nałożonych na
kolumny tablicowe, które nie dotyczą innych typów danych ( np. nie mogą być one
przekazywane lub zwracane przez procedury pamiętane). Warto ostrożnie
wyważyć wszystkie za i przeciw wprowadzaniu do struktury swojej bazy danych
takich, utrudniających manipulowanie danymi, elementów.

Specjalne wartości domyślne kolumn (special column defaults)

Oprócz definiowania stałych jako wartości domyślnych kolumn, InterBase
umożliwia użycie trzech specjalnych słów kluczowych, definiujących wartość
domyślną w kolumnie:

USER,TODAY and NOW

.

USER

oznacza nazwę

aktualnego użytkownika;

TODAY

- aktualną datę (analogicznie do funkcji Delphi -

Date

), natomiast

NOW

- aktualną datę i czas ( zgodna z funkcją

Now

w Delphi).

Poniżej przedstawiamy przykład zastosowania omówionych elementów:

CREATE TABLE REPORTLOG
(ReportUser VARCHAR(20) DEFAULT USER,
ReportData DATE DEFAULT "TODAY",
ReportDateTime DEFAULT "Now"

Warto zaznaczyć, że

"TODAY"

oraz

"NOW

" muszą być podane w cudzysłowie,

natomiast

USER

nie. Tekst

USER

podany w cudzysłowie będzie oznaczał wartość

"USER"

a nie nazwę aktualnego użytkownika.

Dodawanie i usuwanie kolumn

Dodając lub usuwając kolumnę z istniejącej tabeli korzystamy z instrukcji

ALTER

TABLE

. W przeciwieństwie do niektórych serwerów baz danych (np. Microsoft

SQL Server) InterBase Server umożliwia usuwanie kolumn. Składnia dla
dodawania kolumn wygląda następująco :

ALTER TABLE CUSTOMER
ADD PhoneNumber char(10)

natomiast dla usuwania:

ALTER TABLE CUSTOMER
DROP PhoneNumber

background image

516

Część III

Oczywiście nie można rozszerzyć niepustej tabeli o nową kolumnę z zastrzeżeniem

NOT NULL.

Wtedy bowiem nie można byłoby odpowiednio uzupełnić

umieszczonych w niej wierszy

.

Więzy (constrains)

Więzy to mechanizmy, dzięki którym możemy ograniczyć rodzaj danych
umieszczanych w kolumnie lub powiązać je ze sobą. Pozwalają także określić
wartości domyślne dla kolumn. Definiuje się je dołączając odpowiednie instrukcje
do

CREATE TABLE

albo

ALTER TABLE

. Jednym z przykładów nakładania

więzów jest tworzenie klucza głównego:

ALTER TABLE CUSTOMER
ADD PRIMARY KEY (CustomerNumber)

W tym przykładzie zdefiniowaliśmy klucz główny dla tabeli CUSTOMER jako
pole

CustomerNumber

. Dzięki temu, na bazie pola

CustomerNumber

zostanie utworzony unikalny indeks. Oczywiście do zdefiniowania klucza
głównego tabeli nie można użyć kolumny, która zezwala na użycie wartości

NULL

.

Klucz obcy definiuje kolumnę w jednej tabeli, której wartości muszą znajdować
się innej tabeli. Nie określa jednoznacznie wierszy, tak jak jest to w przypadku
klucza głównego. Musi być jednak kluczem głównym lub unikalnym w tabeli, do
której się odnosi. Dodanie klucza obcego powoduje, że SQL Server buduje wtórny
indeks, bazujący na polu kluczowym. Oto odpowiedni przykład:

ALTER TABLE SALE
ADD CONSTRAINT INVALID_CUSTOMER_NUMBER FOREIGN KEY

(CustomerNumber)REFERENCES CUSTOMER

W przykładzie zdefiniowano pole

CustomerNumber

w tabeli SALE, jako klucz

obcy odnoszący się do tej samej kolumny w tabeli CUSTOMER. Nałożone więzy
powodują, że aby numer klienta ( ang. customer number) mógł być wprowadzony
do tabeli SALE, musi najpierw istnieć w tabeli CUSTOMER. Także numery
używane w tabeli SALE nie mogą zostać usunięte z tabeli CUSTOMER.
Możliwość wymuszenia zależności pomiędzy dwiema tabelami przez
zadeklarowanie ich relacji w SQL jest nazywana deklaratywną spójnością
referencyjną (ang. declarative referential integrity). Ten termin znaczy po prostu,
że spójność danych w tabelach związanych relacją jest zapewniana przez
zdefiniowanie (lub zadeklarowanie) tej relacji w bazie, a nie przez kod programu.

Trzeci typ więzów pozwala ustalić zakres dozwolonych wartości dla
wprowadzanych danych np.

background image

Rozdział 17 Delphi w Interbase

517

ALTER TABLE CUSTOMER
ADD CONSTRAINT INVALID_STATE CHECK (State in ('OK', 'AR',

'MO'))

Zwracamy uwagę na celowość użycia elementów negacji w

konwencji

nazewniczej dotyczącej więzów. Oprogramowanie pracujące po stronie
użytkownika, które zapobiega naruszeniu więzów, ma dostarczać użytkownikowi
łatwą do poprawnego zinterpretowania informację. Gdyby informacja o błędzie
była sygnowana

VALID_STATE,

użytkownik mógłby się nie zorientować, co jest

przyczyną problemu. Dobrze dobrana nazwa ograniczenia, która służy jako
informacja zwrotna, będzie dla użytkownika wystarczającą wskazówką, w jaki
sposób próbowano naruszyć więzy. Dzięki temu nie musimy zastępować, swoimi
własnymi, komunikatów generowanych przez wyjątki obsługiwane w Delphi.

Testowanie funkcjonowania więzów

Każde więzy nałożone na bazę powinny zostać sprawdzone. Najlepszym testem
będzie próba ich naruszenia. Np. aby sprawdzić więzy

INVALID_STATE,

zdefiniowane powyżej, wprowadzamy następującą instrukcję w

programie

WISQL:

INSERT INTO CUSTOMER (CustomerNumber,State)
VALUES(123,'CA')

Ponieważ istniejące więzy pozwalają tylko na wprowadzenie wartości

'OK',

'AR' i 'MO',

to próba umieszczenia tego wiersza w bazie powinna wywołać

komunikat błędu.

Jeśli wprowadzone więzy nie funkcjonują, należy przede wszystkim sprawdzić,
czy zostały one poprawnie zapisane w bazie oraz przeanalizować ich definicje.

Tworzenie indeksów

Do budowania indeksów w InterBase SQL służy instrukcja

CREATE INDEX.

Jej

podstawowa składnia wygląda następująco:

CREATE INDEX SALE02 ON SALE (SaleDate)

SALE02

jest nazwą nowego indeksu,

SALE

- tabelą, dla której budujemy indeks

a

SaleDate -

kluczem indeksu. Należy zaznaczyć, że nazwa indeksu w systemie

InterBase musi być unikalna w bazie, w której jest on umieszczony.

Instrukcja

CREATE UNIQE INDEX

tworzy indeks zapewniający unikalność

klucza np:

CREATE UNIQE INDEX SALE01 ON SALE (SaleNumber)

background image

518

Część III

Domyślnie indeks jest uporządkowany według rosnących wartości klucza.
InterBase pozwala także na uporządkowanie malejące, jeśli przy tworzeniu
indeksu użyjemy słowa kluczowego

DESCENDING

np.

CREATE DESCENDING INDEX SALE03 ON SALE (Amount)

Tak utworzony indeks przyspiesza wykonanie niektórych zapytań, np.:

SELECT * FROM SALE
ORDER BY Amount DESCENDING

Włączanie i wyłączanie indeksu

InterBase dysponuje użytecznym mechanizmem wyłączania indeksu. Przyspiesza
to wprowadzanie zmian do tabeli podstawowej. Wyłączony indeks włącza się (
i przy tym przebudowuje) dopiero po wprowadzeniu całej partii nowych danych.
Dzięki temu można szybko dodać do tabeli dużą liczbę wierszy, unikając
aktualizacji indeksu przy każdym nowym wierszu. Oto przykład wyłączenia
indeksu:

ALTER INDEX SALE02 INACTIVE

i ponownego włączenia:

ALTER INDEX SALE02 ACTIVE

Ponowne uaktywnienie indeksu wymusza jego przebudowę. Należy zaznaczyć, że
wyłączenie indeksu jest możliwe dopiero po jego całkowitym zwolnieniu - nie
może on być wykorzystywany przez klucz główny lub obcy. Aby wyłączyć indeks
używany przez więzy należy najpierw je usunąć.

Wprowadzanie danych

Instrukcja

INSERT

służy do wprowadzania danych do tabeli InterBase. Każde

wystąpienie klauzuli

VALUES

w instrukcji

INSERT

umożliwia dodanie jednego

wiersza danych. Można też wprowadzić od razu kilka wierszy, wybierając je
z innej tabeli. W poniższym przykładzie dodano dane do wszystkich naszych tabel.
Najpierw trzy wiersze do tabeli CUSTOMER (posłużymy się WISQL):

INSERT INTO CUSTOMER (CustomerNumber, LastName, FirstName,

StreetAddress, City, State, Zip)

VALUES(1,'Doe','John','123 Sunnylane','Anywhere','MO',

'73115')

INSERT INTO CUSTOMER (CustomerNumber, LastName, FirstName,

StreetAddress, City, State, Zip)

background image

Rozdział 17 Delphi w Interbase

519

VALUES(2,'Doe','Jane','123 Sunnylane','Anywhere','MO',

'73115')

INSERT INTO CUSTOMER (CustomerNumber, LastName, FirstName,

StreetAddress, City, State, Zip)

VALUES(3,'Philgates','Buck','57 Riverside','Reo','AR',

'65803')

Teraz dodamy trzy wiersze do tabeli ITEM i:

INSERT INTO ITEM(ItemNumber, Description, Price)
VALUES(1001,'Zoso LP',13.45)

INSERT INTO ITEM(ItemNumber, Description, Price)
VALUES(1002,'White LP',67.90)

INSERT INTO ITEM(ItemNumber, Description, Price)
VALUES(1003,'Bad Co. LP',11.45)

W końcu dodamy cztery wiersze do tabeli SALE:

INSERT INTO SALE (SaleNumber, SaleDate, CustomerNumber,

ItemNumber, Amount)

VALUES(101,'10/18/90',1,1001,13.45)

INSERT INTO SALE (SaleNumber, SaleDate, CustomerNumber,

ItemNumber, Amount)

VALUES(102,'02/27/92',2,100,67.90)

INSERT INTO SALE (SaleNumber, SaleDate, CustomerNumber,

ItemNumber, Amount)

VALUES(103,'05/20/95',3,1003,11.45)

INSERT INTO SALE (SaleNumber, SaleDate, CustomerNumber,

ItemNumber, Amount)

VALUES(104,'11/27/97',4,1004,67.90)

Warto zauważyć, że nie trzeba uwzględniać wszystkich kolumn ani ich porządku
ustalonego przy tworzeniu tabeli ale lista podanych wartości musi być zgodna pod
względem liczby elementów i ich uporządkowania z listą kolumn w instrukcji

INSERT

, np.:

INSERT INTO ITEM (Price, ItemNumber)
VALUES(13.45, 1001)

background image

520

Część III

Wartości specjalne

InterBase umożliwia korzystanie z domyślnych wartości specjalnych kolumn

USER

,

TODAY

i

NOW

, jak to zaprezentowano w poniższym przykładzie:

INSERT INTO REPORTLOG VALUES(USER, "TODAY", "NOW")

Instrukcja UPDATE

Instrukcja SQL

UPDATE

służy do modyfikacji danych w tabeli. Jej klauzula

WHERE

umożliwia wybór modyfikowanych wierszy. Oto odpowiedni przykład:

UPDATE CUSTOMER
SET Zip='65803'
WHERE City='SpringField'

Klauzula

WHERE

w

instrukcji

UPDATE

pozwala ograniczyć liczbę

modyfikowanych wierszy nawet do jednego ( zależnie od danych i warunku),
natomiast pomijając ją domyślnie zmodyfikujemy wszystkie rekordy:

UPDATE CUSTOMER
SET State='MO'

Poprawiając dane w kolumnie można korzystać z wartości innych kolumn danej
tabeli (także z tej kolumny). Załóżmy, że chcemy zwiększyć cenę każdego
produktu z tabeli ITEM o 7 %. Modyfikację tę można wykonać następująco:

UPDATE ITEM
SET Price=Price+(Price*.07)

Podobnie jak

INSERT

, instrukcja

UPDATE

umożliwia wykorzystanie specjalnych

wartości stałych kolumnowych InterBase, jak pokazano w przykładzie:

UPDATE SALE
SET Amount=Amount-(Amount*.25)
WHERE SaleDate>="TODAY"-30

Dzięki

TODAY

dokonano wyboru aktualizowanych wierszy. W ten sposób zostaną

zmodyfikowane wszystkie transakcje sprzedaży z ostatnich 30 dni.

Instrukcja DELETE

Dzięki instrukcji SQL

DELETE

mamy możliwość usuwania wierszy z tabeli. Np. -

aby opróżnić tabelę CUSTOMER wystarczy napisać:

DELETE FROM CUSTOMER

background image

Rozdział 17 Delphi w Interbase

521

Instrukcja

DELETE

może też zawierać klauzulę

WHERE,

ograniczającą zakres

usuwanych wierszy. Oto odpowiedni przykład:

DELETE FROM CUSTOMER
WHERE LastName<>'Doe'

Kontrola Transakcji

Grupa powiązanych zmian w bazie nazywa się formalnie transakcją. Własne
transakcje inicjujemy za instrukcją

BEGIN TRANSACTION

. Instrukcja

COMMIT

służy do zachowania zmian dokonywanych w czasie transakcji, a instrukcja

ROLLBACK

pozwala na ich wycofanie. Obie odnoszą się tylko do zmian

dokonanych od chwili wywołania ostatniej instrukcji

COMMIT

.

ROLLBACK

nie

spowoduje wycofania zmian przyjętych poprzedzającymi ją instrukcjami

COMMIT.

InterBase WISQL otwiera transakcję automatycznie (używając odpowiednika
instrukcji

SET TRANSACTION

) przy pierwszym załadowaniu. Przy opuszczaniu

programu użytkownik jest proszony o

zatwierdzenie dokonanych zmian.

W każdym momencie pracy z WISQL można zapisać lub wycofać wprowadzone
zmiany, posługując się odpowiednio poleceniami

Commit Work

i

Rollback Work

z menu

File

.

UWAGA:

Oprócz zwykłej modyfikacji danych kontrola transakcji w InterBase uwzględnia
także instrukcje DDL (Data Definition Language). Za ich pomocą można
definiować i tworzyć obiekty bazy danych - takie, jak tabele i indeksy. Jeśli obiekt
zostanie utworzony wewnątrz transakcji, to w przypadku jej wycofania jest
usuwany. Ta zmiana jest natychmiast widoczna w całej bazie i na każdym
poziomie izolacji transakcji (Transaction Isolation Level-TIL), aktywnym w danej
chwili.

Instrukcja SELECT

Instrukcja SQL

SELECT

pobiera dane z określonych kolumn tabeli. Pozwoli nam

więc sprawdzić zawartość trzech naszych tabel. W

tym celu wykonajmy

trzykrotnie instrukcję o składni

SELECT * FROM tablename

, zamieniając za

każdym razem

tablename

na nazwę odpowiedniej tabeli (CUSTOMER

,

SALE

oraz ITEM). Jeśli wcześniej dodaliśmy proponowane dane, to każda z powstałych
w ten sposób tabel roboczych powinna mieć co najmniej trzy wiersze.

background image

522

Część III

SELECT

* zwraca cała tabelę. Jeśli gwiazdkę zastąpimy listą nazw pól

oddzielonych przecinkami, to otrzymamy dane tylko z wybranych pól np.:

SELECT CustomerNumber, LastName, State FROM CUSTOMER

Wyrażenia kolumnowe

Instrukcja

SELECT

w SQL Server umożliwia podanie na liście kolumn nie tylko

samych nazw, ale także wyrażeń arytmetycznych, zbudowanych z wartości
kolumn, stałych i funkcji. Podajemy tutaj taki przykład zastosowania instrukcji

SELECT

, zwracającej rekordy z tabeli SALE, z wartością sprzedaży powiększoną

o $15 (opłatę za dostarczenie towaru):

SELECT SaleNumber, SaleDate, Amount+15 AmountPlusShipping
FROM SALE

Funkcje sumaryczne

Funkcje sumaryczne wykonują pewne obliczenia na zbiorach danych. Przykładami
takich funkcji są

COUNT, SUM, AVG, MIN

oraz

MAX

. Podamy teraz kilka

przykładów ich zastosowania:

SELECT COUNT(*) FROM CUSTOMER

To zapytanie daje w wyniku liczbę klientów w pliku.

SELECT MAX(Amount) FROM SALE

To z kolei podaje największą wartość sprzedaży w dolarach.

SELECT SUM(Amount) FROM SALE

Natomiast wynikiem tego zapytania jest całkowita wartość sprzedaży w dolarach.

Klauzula WHERE

Klauzula SQL

WHERE

umożliwia wybranie wierszy zwracanych przez instrukcję

SELECT

. Oto przykład:

SELECT * FROM CUSTOMER
WHERE State='MO'

W wyniku otrzymujemy tylko tych klientów, którzy mieszkają w Missouri (symbol
'MO').

SELECT * FROM CUSTOMER
WHERE StreetAddress LIKE '%Sunny%'

background image

Rozdział 17 Delphi w Interbase

523

Rezultatem tego zapytania będą dane klientów, u których w

polu

StreetAddress

występuje słowo

Sunny

. Należy pamiętać, że porównanie

znaków uwzględnia różnice pomiędzy wielkimi i małymi literami. Zawsze jednak
można - do zamiany wszystkich liter w kolumnie i poszukiwanym wzorcu na duże
- zastosować funkcję

UPPER

.

Oto dalsze przykłady:

SELECT * FROM SALE
WHERE Amount>500

W wyniku otrzymujemy listę wszystkich transakcji, których kwota przekroczyła
500$.

SELECT

* FROM SALE

WHERE SaleDate BETWEEN '10/18/90' AND '05/20/95'

To zapytanie zwraca dane o wszystkich transakcjach dokonanych pomiędzy 18
października 1990 r. a 20. maja 1995 r. włącznie.

Złączenia (Joins)

Klauzula

WHERE

jest także wykorzystywana do łączenia tabel. Przy złączeniu

składnia klauzuli

WHERE

jest inna niż w podstawowej instrukcji

SELECT

.

Formułując odpowiednie warunki w klauzuli

WHERE

określamy dodatkowe tabele

w klauzuli

SELECT FROM

i łączymy pola będące ze sobą w relacji

.

Dobrze

ilustruje to następujący przykład:

SELECT CUSTOMER.CustomerNumber, SALE.Amount
FROM CUSTOMER, SALE
WHERE CUSTOMER.CustomerNumber=SALE.CustomerNumber

Zauważmy, że do klauzuli

FROM

włączono tabelę SALE oraz - do złączenia tabel

CUSTOMER i SALE poprzez pole

CustomerNumber

- użyto znaku równości.

Tabela wymieniona po lewej stronie znaku równości nazywana jest tabelą
zewnętrzną, a po prawej - wewnętrzną. Ze względu na ich pozycję w stosunku do
znaku równości często używa się określenia prawa i lewa. O złączeniu mówi się
lewa do prawej
lub złączenie lewostronne. Jest to najczęściej używane złączenie
w zapytaniach SQL

Złączenia wewnętrzne(inner)a zewnętrzne (outer)

Wspomniane powyżej złączenie lewostronne formalnie nazywa się złączeniem
wewnętrznym. Złączenie wewnętrzne daje w wyniku tylko wiersze, dla których
spełniony jest warunek złączenia. Natomiast złączenie zewnętrzne uwzględnia też
wiersze, dla których warunek nie został spełniony. W złączeniu zewnętrznym, jeśli
nie znajdziemy pasujących wierszy w tabeli wewnętrznej, to kolumny z tabeli

background image

524

Część III

wewnętrznej dołączane będą z wartością NULL. W zależności od rodzaju
złączenia zewnętrznego - tzn. left (lewostronne) lub right (prawostronne) -
wartościami

NULL

są odpowiednio uzupełniane wszystkie wiersze lewej albo

prawej tabeli, dla których nie był spełniony warunek złączenia.

Składnia złączenia w ANSI

Składnia ANSI definiuje specjalne operatory złączeń, umieszczane w klauzuli

FROM

. Składnię dla lewostronnego wewnętrznego złączenia zaprezentujemy na

przykładzie:

SELECT CUSTOMER.CustomerNumber, SALE.Amount
FROM CUSTOMER LEFT JOIN SALE
ON CUSTOMER.CustomerNumber=SALE.CustomerNumber

Należy zaznaczyć, że domyślnie przyjmuje się słowo kluczowe

INNER

(złączenie

wewnętrzne). Jak pokazano wcześniej, InterBase także używa takiej składni do
zdefiniowania lewostronnego wewnętrznego złączenia :

SELECT CUSTOMER.CustomerNumber, SALE.Amount
FROM CUSTOMER, SALE
WHERE CUSTOMER.CustomerNumber=SALE.CustomerNumber

Składnię dla lewostronnego złączenia zewnętrznego przedstawiamy w poniższym
przykładzie:

SELECT CUSTOMER.CustomerNumber, SALE.Amount
FROM CUSTOMER LEFT OUTER JOIN SALE
ON CUSTOMER.CustomerNumber=SALE.CustomerNumber

Dla określenia prawostronnego złączenia zewnętrznego wystarczy po prostu
zamienić

LEFT

na

RIGHT

. Oczywiście nie ma potrzeby rozróżniania

prawostronnego i

lewostronnego złączenia wewnętrznego, bowiem zgodnie

z podaną zasadą dają one ten sam wynik.

Złączenia wielopoziomowe (Multi-Tier Joins)

Złączenia wielopoziomowe korzystają z więcej niż dwóch tabel. Tabela A jest
złączana z tabelą B, a ta z kolei jest - z tabelą C. Rozważmy następujące zapytanie:

SELECT C.LastName, C.FirstName, I.Description, S.Amount
FROM CUSTOMER C,
SALE

S,

ITEM

I

WHERE C.CustomerNumber=S.CustomerNumber
and S.ItemNumber=I.ItemNumber

background image

Rozdział 17 Delphi w Interbase

525

W tym zapytaniu

CUSTOMER

i

SALE

złączone są przez wspólny klucz - pole

CustomerNumber

a

SALE

i

ITEM

przez

ItemNumber

. W efekcie wszystkie

trzy tabele utworzą jeden zbiór wynikowy.

Samozłączenia (Self-Joins)

Oprócz złączenia z innymi tabelami, tabela może być złączana sama ze sobą. Ten
rodzaj złączenia nazywa się samozłączeniem. Rozważmy następujące zapytanie:

SELECT S.CustomerNumber, S.Amount,
(S.Amount/SUM(S2.Amount))*100 Precentage
FROM SALE S,
SALE

S2

WHERE S.CustomerNumber=S2.CustomerNumber
GROUP BY S.CustomerNumber, S.Amount

To zapytanie podaje kwoty wszystkich zakupów dokonanych przez klientów wraz
z rozbiciem procentowym w stosunku do całej kwoty zapłaconej przez danego
klienta. Budując takie zapytanie w ramach jednej instrukcji

SELECT

musimy

posłużyć się samozłączeniem. Najpierw jest tworzona i grupowana indywidualna
statystyka, a potem tabela SALE złączana jest ze sobą dla uzyskania łącznej kwoty
zakupów każdego klienta. To pozwala już obliczyć odpowiednią wartość
procentową, która wystąpi w wyniku zapytania.

Złączenia z użyciem innych operatorów (Theta Joins)

W warunku złączenia oprócz najczęściej stosowanego operatora porównania „jest
równe” (=) mogą wystąpić inne - zwykle jest to operator " jest różne" (<>).Podany
przykład prezentuje takie złączenie, pokazując jednocześnie wykorzystanie
samozłączenia:

SELECT C.CustomerNumber, S.Amount, (S2.Amount) OTHERS
FROM CUSTOMER C,
SALE

S,

SALE

S2

WHERE C.CustomerNumber=S.CustomerNumber
AND C.CustomerNumber<>S2.CustomerNumber
GROUP BY C.CustomerNumber, S.Amount

Faktycznie to zapytanie zawiera dwa złączenia. Pierwsze - pomiędzy

CUSTOMER

i

SALE

- aby uzyskać kwotę zakupu dla każdego klienta. Następne zaś (theta join)

- do obliczenia sumy kwot wszystkich zakupów, które nie zostały zrobione przez
klienta. Ponieważ stosuje się dwa różne typy złączenia do tej samej tabeli, więc
zapytanie, dla SALE, korzysta z dwóch różnych aliasów.

background image

526

Część III

Złączenia pełne (Full Joins)

Pełne złączenie pozwala łączyć wiersze z dwóch tabel bez klauzuli

WHERE

. Jest

ono przydatne w przypadku łączenia tabel powiązanych relacjami. Jeśli żadna
z tabel nie zawiera wszystkich interesujących nas wierszy, wtedy łącząc je poprzez
zewnętrzne pełne złączenie otrzymamy wszystkie wiersze. Jest to po prostu
kombinacja złączenia prawo i lewostronnego. Oto przykład:

SELECT DISTINCT C.CustomerNumber, S.SaleNumber
FROM CUSTOMER C FULL JOIN SALE S
ON 1=1

UWAGA

Powyższy prosty kod zawiera tożsamość 1=1, bowiem analizator składniowy
InterBase wymaga klauzuli ON we wszystkich złączeniach, nawet pełnych, dla
których praktycznie nie jest to konieczne.

Iloczyn kartezjański

Iloczyn kartezjański jest wynikiem połączenia wszystkich wierszy z jednej tabeli
ze wszystkimi wierszami innej. Zwykle taki zbiór otrzymujemy przypadkowo, gdy
opuścimy lub niewłaściwie sformułujemy warunek złączenia. Oto odpowiedni
przykład:

SELECT SALE.SaleNumber, ITEM.ItemNumber
FROM SALE, ITEM
ORDER BY SaleNumber, ItemNumber

Dla tabel z dużą ilością danych obliczanie iloczynu kartezjańskiego może
zablokować serwer na tak długo, że konieczne będzie zamknięcie połączenia albo
zatrzymanie realizacji zapytania. W niektórych systemach zatrzymanie procesu
jest możliwe tylko przez zrestarowanie komputera serwera. Należy więc unikać
tworzenia iloczynu kartezjańskiego - zwłaszcza wtedy, gdy pracujemy z dużymi
tabelami.

Podzapytania (Subqueries)

Podzapytanie to instrukcja

SELECT

umieszczona w klauzuli

WHERE

innej

instrukcji

SELECT

. Ogólnie podzapytania to zapytania zwracające dane, które nie

są końcowym wynikiem, lecz będą wykorzystywane w dalszej części instrukcji.
Oto przykład:

SELECT * FROM CUSTOMER
WHERE CustomerNumber IN (SELECT CustomerNumber FROM SALE)

background image

Rozdział 17 Delphi w Interbase

527

Pewne operatory funkcjonują tylko w podzapytaniach. S¹ to

ANY, ALL, SOME,

EXISTS i SINGULAR

. Chociaż słowo kluczowe

ALL

jest także używane

w instrukcji

SELECT,

to jako operator występuje tylko w podzapytaniach.

GROUP BY

Ponieważ SQL jest językiem zapytań zorientowanym na przetwarzanie zbiorów
(set - oriented), instrukcje grupujące dane są jego integralną częścią. Często osoby
tworzące bazy danych i pracujące z innymi systemami DBMS uważają takie
podejście za nietypowe, bowiem są przyzwyczajone do procedur przetwarzających
dane wiersz po wierszu. W wielu programach działających na komputerach PC,
aby zebrać dane sumaryczne iteruje się pętlę przez całą tabelę. Podejście SQL jest
zupełnie inne. Niekiedy pojedyncza instrukcja SQL zastępuje 10 lub nawet 50 linii
kodu programu napisanego w dBase. Jest to możliwe dzięki instrukcji

SELECT

,

klauzuli

GROUP BY

oraz funkcjom sumarycznym SQL. Klauzula

GROUP BY

pozwala definiować grupy wyjściowe wierszy, do których odnoszą się funkcje
sumaryczne użyte w klauzuli

SELECT

. Następny przykład pokazuje zastosowanie

klauzuli

GROUP BY

:

SELECT CUSTOMER.CustomerNumber, SUM(SALE.Amount) TotalSale
FROM CUSTOMER, SALE
WHERE CUSTOMER.CustomerNumber=SALE.CustomerNumber
GROUP BY CUSTOMER.CustomerNumber

Rezultatem tego zapytania jest lista wszystkich klientów wraz z sumaryczną
wartością transakcji każdego klienta.

Oczywiście nasuwa się pytanie, które pola połączyć klauzulą

GROUP BY

. InterBase

Server oraz ANSI SQL wymagają, aby klauzula

GROUP BY

zawierała wszystkie

kolumny wymienione na liście kolumn instrukcji

SELECT

, które nie są funkcjami

sumarycznymi. W przypadku korzystania z klauzuli

GROUP BY

na liście kolumn

instrukcji

SELECT

powinna znaleźć się choć jedna funkcja sumaryczna. Jeśli ten

warunek nie jest spełniony, InterBase Server uniemożliwia zastosowanie klauzuli

GROUP BY.

HAVING

Klauzula

HAVING

w instrukcji

SELECT

służy do selekcji wierszy zwracanych

przez klauzulę

GROUP BY

. Zależność między klauzulami

GROUP BY

oraz

HAVING

przypomina relację pomiędzy instrukcją

SELECT

a klauzulą

WHERE

.

Klauzula

HAVING

działa podobnie jak klauzula

WHERE,

ale na zbiorze

wynikowym, a nie na wierszach w tabelach zapytania.

Ogólnie

HAVING

jest mniej efektywne niż

WHERE

, ponieważ selekcjonuje zbiór

wynikowy, po tym jak zostanie on zgrupowany, zaś

WHERE

czyni to najpierw. Są

background image

528

Część III

jednak sytuacje, w których korzystamy z klauzuli

HAVING

. Przeanalizujmy

poniższy przykład:

SELECT CUSTOMER.LastName, COUNT(*) NumberWithName
FROM CUSTOMER
GROUP BY CUSTOMER.LastName
HAVING COUNT(*)>1

HAVING

wykorzystujemy przy selekcji wierszy otrzymywanych przez zapytanie

bazujące na funkcji sumarycznej. Zastosowanie

WHERE

jest niemożliwe, bowiem

potrzebna informacja nie istnieje - aż do momentu wykonania zapytania
i obliczenia odpowiednich wartości.

ORDER BY

Klauzula ta służy do odpowiedniego posortowania zbioru wynikowego. Oto
przykład:

SELECT * FROM CUSTOMER
ORDER BY State

Bez

ORDER BY

nie ma żadnej gwarancji, że wiersze zostaną odpowiednio

posortowane. Wtedy nawet ta sama instrukcja

SELECT,

wywołana dwukrotnie,

może stworzyć zbiory wynikowe, za każdym razem uporządkowane inaczej.

Aliasy kolumn

W kilku prezentowanych wcześniej przykładach używaliśmy logicznych nazw
kolumn, w których umieszczaliśmy wyniki obliczeń funkcji sumarycznych, jak

COUNT()

czy

SUM().

Etykiety tego typu nazywamy aliasami kolumn. Dzięki

nim zapytanie i jego wynik są czytelniejsze. W InterBase SQL alias kolumny
umieszcza się bezpośrednio po prawej stronie odpowiadającej mu kolumny - na
liście pól instrukcji

SELECT

. Na przykład w podanym poniżej zapytaniu aliasem

wartości funkcji sumarycznej

COUNT()

jest etykieta

NumberWithName:

SELECT CUSTOMER.LastName, COUNT(*) NumberWithName
FROM CUSTOMER
GROUP BY CUSTOMER.LastName
HAVING COUNT(*)>1

Aliasy można stosować nie tylko dla funkcji sumarycznych, lecz dla każdej
pozycji w zbiorze wynikowym, np.:

SELECT CUSTOMER.LastName LName, COUNT(*) NumberWithName
FROM CUSTOMER
GROUP BY CUSTOMER.LastName

background image

Rozdział 17 Delphi w Interbase

529

W tym zapytaniu zastąpiliśmy w zbiorze wynikowym nazwę kolumny

LastName

przez jej alias

LName

. Aliasów nie można jednak stosować w innych częściach

zapytania, takich jak klauzula

WHERE

czy

GROUP BY

. Wtedy musimy posłużyć

się nazwą kolumny lub wartością.

Aliasy tabel

Składnia instrukcji

SELECT

umożliwia korzystanie ze skrótu, zamiast podawania

pełnej nazwy tabeli. Nazywamy go aliasem tabeli. Jest definiowany w klauzuli

FROM

instrukcji

SELECT

i

umieszczany bezpośrednio po prawej stronie

właściwej nazwy, tak jak w poniższym przykładzie:

SELECT C.LastName, COUNT(*) NumberWithName
FROM CUSTOMER C
GROUP BY C.LastName

Może dziwić fakt, że alias występuje na liście pól instrukcji

SELECT,

czyli zanim

go zdefiniowano. Powinniśmy jednak pamiętać, że odwołanie się do obiektów
bazy danych musi nastąpić przed wykonaniem zapytania

Perspektywy (Views)

Perspektywa SQL składa się z instrukcji

SELECT

, którą można traktować jak

tabelę i, w

dalszej kolejności, zapytania z

innymi instrukcjami

SELECT

.

W pewnych sytuacjach może być ona parametrem instrukcji

INSERT, DELETE

i UPDATE

. Perspektywa nie zapamiętuje jednak żadnych danych. Jest ona tylko

pewną konstrukcją logiczną. Można o niej myśleć jako o małym programie
w języku SQL, uruchamianym przy każdym zapytaniu stworzonym na jej bazie.
Jest podobna do procedury wyboru - omówionej w następnej sekcji " Procedury
pamiętane". Gdy jest wykonywane zapytanie posługujące się perspektywą,
optymalizator zapytań tworzy najpierw perspektywę, łączy ją z właściwym
zapytaniem i optymalizuje obie czynności wykonując je jako jedno zapytanie.

Perspektywy w SQL tworzy się instrukcją

CREATE VIEW,

np.:

CREATE VIEW MOCUSTOMERS AS
SELECT *
FROM CUSTOMER
WHERE State='MO'

Perspektywa może zostać wykorzystana w zapytaniu jak zwykła tabela - np.:

SELECT * FROM MOCUSTOMERS

Mimo braku klauzuli

WHERE w

zapytaniu, zbiór wynikowy uwzględnia

oczywiście klauzulę

WHERE,

podaną w definicji perspektywy.

background image

530

Część III

Instrukcja

SELECT,

tworząca perspektywę, ma prawie takie same możliwości

jak podstawowa instrukcja

SELECT

. Nie może tylko korzystać z klauzuli

ORDER

BY

. To ograniczenie odnosi się do wszystkich omawianych w tym rozdziale

serwerów baz danych.

Dodatkowe ograniczenia obowiązują przy tworzeniu perspektyw
modyfikowalnych.

„Instrukcja

SELECT

może dotyczyć tylko jednej tabeli lub innej

modyfikowalnej perspektywy.

„Kolumny, które nie zostały włączone do perspektywy, muszą dopuszczać

wartość

NULL

, aby było możliwe wykonanie instrukcji

INSERT.

„Instrukcja

SELECT

użyta w

definicji perspektywy nie może zawierać

podzapytań, predykatu

DISTINCT

, klauzuli

HAVING

, funkcji sumarycznych,

złączeń, funkcji użytkownika oraz procedur pamiętanych.

Tworząc modyfikowalną perspektywę, można ograniczyć poprawianie lub
dodawanie wierszy do wartości spełniających zadane przez nią warunki. Serwer
blokuje wtedy wszelkie zmiany wykraczające poza perspektywę. W tym celu
wystarczy - w instrukcji

CREATE VIEW

- dodać klauzulę

WITH CHECK

OPTION

, np.:

CREATE VIEW MOCUSTOMERS AS
SELECT *
FROM CUSTOMER
WHERE State='MO'
WITH CHECK OPTION

W ramach zdefiniowanej perspektywy będzie można dodawać tylko takie rekordy,
dla których

State

=

'MO'

. Nie ma także możliwości zmiany wartości pola

State

Procedury pamiętane (Stored Procedures)

Procedury pamiętane są kompilowanymi programami SQL (często zawierającymi
wiele instrukcji SQL), przechowywanymi wraz z innymi obiektami bazy danych.
W InterBase występują dwa podstawowe rodzaje tych procedur: procedury
wyboru
(ang. select procedures) i procedury wykonywalne (ang. executable
procedures).
Procedur wyboru można użyć zamiast tabel lub perspektyw
w instrukcji SELECT. Ponadto muszą one zwracać wynik ( jedną lub wiele
wartości). Natomiast w przypadku procedur wykonywalnych nie jest to konieczne.

Procedury pamiętane tworzy się instrukcją

CREATE PROCEDURE

. Poniżej

przedstawiamy przykład procedury w InterBase:

background image

Rozdział 17 Delphi w Interbase

531

CREATE PROCEDURE listcustomers RETURNS (LastName CHAR(30),

FirstName CHAR(30))

AS BEGIN
FOR SELECT LastName, FirstName FROM CUSTOMER
INTO :LastName, :FirstName
DO SUSPEND;
END

Dla procedury z parametrami składnia instrukcji ulega drobnej modyfikacji:

CREATE PROCEDURE listcustomersbystate (LastName CHAR(30),

FirstName CHAR(30))

RETURNS (LastName CHAR(30), FirstName CHAR(30))
AS BEGIN
FOR SELECT LastName, FirstName FROM CUSTOMER
WHERE State= :State and LastName like :LastNameMask
INTO :LastName, :FirstName
DO SUSPEND;
END

Procedury wyboru (Select Procedures)

W procedurze wyboru rodzaj zwracanych danych definiuje się po słowie
kluczowym

RETURNS

(jak to pokazano w poniższym przykładzie):

CREATE PROCEDURE listcustomers (State CHAR(2))
RETURNS (LastName CHAR(30))
AS
BEGIN
FOR SELECT LastName
FROM CUSTOMER
WHERE State= :State
INTO :LastName
DO
SUSPEND;
END

Warto zwrócić uwagę, że w powyższym przykładzie konstrukcja

FOR

SELECT ... DO

powoduje przekazanie wierszy wynikowych do miejsca

wywołania. Instrukcja

SUSPEND

przerywa wykonanie procedury - aż do chwili,

gdy wywołanie zażąda następnego wiersza. Wartości przypisane parametrom
wyjściowym zostają przekazane przed przerwaniem realizacji procedury.

Procedury wykonywalne

Procedury wykonywalne różnią się od procedur wyboru tym, że nie wymagają
użycia instrukcji

RETURNS

. Oto przykład procedury wykonywalnej w InterBase

SQL:

background image

532

Część III

CREATE PROCEDURE insertitem (ItemNumber Integer, Description

Char(30), Price Float)

AS
BEGIN

INSERT INTO ITEM (ItemNumber, Description, Price)

VALUES (:ItemNUmber, :Description, :Price);

END

Skrypty

Instrukcje Data Definition Language (DDL), zawierające procedury pamiętane,
warto umieszczać w specjalnych plikach zwanych skryptami. Są to zwykłe pliki
tekstowe, zawierające ciągi poleceń SQL, więc można ich tworzyć korzystając
z dowolnego edytora tekstów. Warto tu przypomnieć, że powinny one zawierać
wszystkie niezbędne instrukcje

CONNECT i SET TERM

. Skrypt SQL można

wykonać, wybierając polecenie

Run an

SQL Script

z menu

File

programu

WISQL. Przykład zawiera listing 17.1

Listing 17.1. Procedura pamiętana w

skrypcie SQL.

CONNECT "C:\DATA\IB\SALES.GDB" USER "SYSDBA" PASSWORD

"masterkey";

SET TERM ^ ;
CREATE PROCEDURE GET_CUSTOMER_BY _STATE (State CHAR(2))
RETURNS (LastName CHAR(30))
AS
BEGIN

FOR SELECT LastName

FROM

CUSTOMER

WHERE State= :State

INTO

:LastName

DO
SUSPEND;
END^
SET TERM ; ^
EXIT;

Instrukcja

CONNECT

na początku pliku ustala połączenie z bazą danych.

Następnie

SET TERM

zmienia znak kończący instrukcje SQL - z domyślnego

średnika (;) na (^). Zmiana ta powoduje, że instrukcje zawarte w przechowywanej
procedurze nie są wykonywane, gdy jest ona dopiero tworzona - za pomocą

CREATE PROCEDURE

. Instrukcja

SET TERM

przywraca domyślny znak

zakończenia instrukcji.

background image

Rozdział 17 Delphi w Interbase

533

Uruchamianie procedur pamiętanych

Procedury pamiętane InterBase uruchamiamy instrukcją

EXECUTE PROCEDURE

.

Jej składnia przedstawia się następująco:

EXECUTE PROCEDURE procedurename parameters

W miejsce

procedurename

należy podać nazwę uruchamianej procedury,

a w miejsce

parameters

jej parametry np.:

EXECUTE PROCEDURE GET_CUSTOMER_BY_STATE "MO"

Ta instrukcja uruchamia procedurę pamiętaną

GET_CUSTOMER_BY_STATE

z parametrem "MO".

Wyjątki (Exceptions)

Wyjątki są mechanizmami przekazującymi aplikacji określone przez programistę
sygnały o błędach, jakie powstały w czasie wykonania procedur pamiętanych
i procedur zdarzeń. W

InterBase wyjątki definiujemy instrukcją

CREATE

EXCEPTION,

natomiast instrukcja

EXCEPTION

służy do ich przechwycenia

i wygenerowania odpowiedniego komunikatu. W listingu 17.2 pokazano sposób
definiowania wyjątku i jego wykorzystania w procedurze przechowywanej.

Listing 17.2. Wyjątek InterBase w

procedurze pamiętanej.

CONNECT "C:\DATA\IB\SALES.GDB" USER "SYSDBA" PASSWORD

"masterkey";

CREATE EXCEPTIONSALE_TOO_LOW;
"The sale amount is to low. Only purchases of $1 or more are
allowed";

SET TERM ^ ;
CREATE PROCEDURE insertsale(SaleNumber int, SaleDate date,

CustomerNumber int, ItemNumber int, Amount float)

AS
BEGIN
If

(:Amount<1)THEN

EXCEPTION

SALE_TOO_LOW;

ELSE
INSERT

INTO

SALE

VALUES (:SaleNumber, :SaleDate, :CustomerNumber,

:ItemNumber, :Amount);

END^
SET TERM ;
EXIT;

background image

534

Część III

Ta procedura ustala minimalną kwotę sprzedaży - 1$. Instrukcja wyboru

IF...THEN

sprawdza, czy kolumna

Amount

w wierszu przygotowanym do

wprowadzenia zawiera kwotę mniejszą niż 1$. Natomiast instrukcja

EXCEPTION

została użyta do zgłoszenia wyjątku

SALE_TOO_LOW

, gdy kwota ta jest mniejsza

niż 1 $.

Procedury zdarzeń (Triggers)

Procedury zdarzeń są to (podobnie jak procedury pamiętane) podprogramy SQL,
uruchamiane gdy dane z zadanej tabeli są wprowadzane, modyfikowane lub
usuwane. Procedura zdarzenia jest skojarzona ze specyficzną operacją
dokonywaną na tabeli (zdarzeniem): wstawianiem wiersza, modyfikacją lub
usuwaniem. Oto odpowiedni przykład w InterBase SQL:

CREATE TRIGGER SALEDelete FOR CUSTOMER
BEFORE DELETE
AS
BEGIN

DELETE FROM SALE

WHERE

CustomerNumber=OLD.CustomerNUmber;

END

Ta procedura zdarzenia likwiduje transakcje danego klienta w tabeli SALE, gdy
jego rekord jest usuwany z tabeli CUSTOMER (usuwanie kaskadowe).Operacja
usuwania z tabeli uruchamia "kaskadowy" proces eliminacji odpowiednich danych
w innych tabelach, połączonych z nią za pomocą wspólnego klucza.

Należy zwrócić uwagę na użycie zmiennej kontekstowej

OLD. O

dwołuje się ona

do bieżącej wartości kolumny w danym wierszu przed wykonaniem operacji

UPDATE

lub

DELETE

. Zmienna kontekstowa

NEW

odwołuje się do nowej

wartości, która ma być wprowadzona realizacją

INSERT

lub

UPDATE

.

Warto też odnotować wystąpienie słowa kluczowego

BEFORE

. Procedura

zdarzenia może być uruchomiona przed (before) lub po (after)

INSERT,

UPDATE, DELETE

.

W InterBase z danym zdarzeniem można skojarzyć do 32768 procedur zdarzenia.
Dlatego w sytuacji, gdy jedno zdarzenie aktywuje wiele procedur obsługi,
powinno się ustalić kolejność ich uruchamiania. Służy do tego słowo kluczowe

POSITION,

które zastosowano w poniższym przykładzie:

CREATE TRIGGER SALEDelete FOR CUSTOMER
BEFORE DELETE
POSITION 0
AS
BEGIN

DELETE FROM SALE

background image

Rozdział 17 Delphi w Interbase

535

WHERE

CustomerNumber=OLD.CustomerNUmber;

END

Numery mogą przyjmować wartości od 0 do 32767, a procedura o niższym
numerze wykonywana jest najpierw. Procedury zdarzeń z tym samym numerem
uruchamiane są w porządku losowym.

Funkcje

InterBase umożliwia rozszerzanie swojej odmiany SQL - przez dołączenie
własnych funkcji. Zasadniczo można zdefiniować własne funkcje w zewnętrznej,
współdzielonej bibliotece funkcji ( w Windows jest to DLL) i udostępniać je za
pomocą instrukcji

DECLARE EXTERNAL FUNCTION

. Przy takim podejściu są

one przechowywane w

naszej bazie danych i

zachowują się jak funkcje

wbudowane. Oto przykład prostej biblioteki DLL, w której zdefiniowano dwie
funkcje.

library IBUDFLIB;

uses
SysUtils,
Classes;

function MaxInt(var Int1, Int2 :Integer) : Integer; far cdecl

export;

begin

if (Int1>Int2) then Result:=Int1

else

Result:=Int2;

end;

function MinInt(var Int1, Int2 :Integer) : Integer; far cdecl

export;

begin

if (Int1<Int2) then Result:=Int1

else

Result:=Int2;

end;
exports
MaxInt,
MinInt;

begin
end.

A teraz przedstawimy przykład skryptu SQL, który udostępni te funkcje dla
InterBase:

background image

536

Część III

CONNECT "C:\DATA\IB\SALES.GDB" USER SYSDBA PASSWORD

masterkey;

DECLARE EXTERNAL FUNCTION MAXINT
INTEGER, INTEGER
RETURNS INTEGER BY VALUE
ENTRY_POINT "MaxInt" MODULE_NAME "IBUDFLIB.DLL";

DECLARE EXTERNAL FUNCTION MININT
INTEGER, INTEGER
RETURNS INTEGER BY VALUE
ENTRY_POINT "MinInt" MODULE_NAME "IBUDFLIB.DLL";

EXIT;

Teraz podamy kilka uwag praktycznych dla osób chcących wzbogacać InterBase
SQL o własne funkcje,:

„InterBase pobiera funkcje z biblioteki DLL, posługując się nazwą funkcji

i rozróżniając w niej wielkie i małe litery. Jeśli nie zadba się o poprawne użycie
wielkich i małych liter w nazwie funkcji, w instrukcji

DECLARE EXTERNAL

FUNCTION

InterBase nie będzie w stanie jej zlokalizować.

„Parametry są przekazywane przez zmienną (zwracamy uwagę na słowo

kluczowe VAR na liście parametrów funkcji MaxInt i MinInt) a nie przez
wartość. Dlatego zadeklarowane funkcje powinny spodziewać się wskaźników
do zmiennych, a nie ich wartości.

„InterBase przyjmuje, że funkcja jest zdefiniowana z wywołaniem

cdecl

. Nie

należy więc używać wywołań

far pascal

,

stdcall

,

or

oraz

safecall,

bowiem nie będą funkcjonowały poprawnie.

„Wyniki mogą być zwracane przez zmienną lub przez wartość. Jeśli wybierzemy

przekazanie przez zmienną, należy pamiętać, aby zwrócić wskaźnik do wartości
a nie samą wartość, inaczej bowiem InterBase zatrzyma się próbując wykonać
funkcję.

Zdefiniowane funkcje

MinInit

i

MaxInit

możemy przetestować, wykonując

następującą instrukcję w WISQL:

SELECT MaxInt(3,5) FROM CUSTOMER;

Składnia InterBase SQL wymaga użycia nazwy co najmniej jednej tabeli
w instrukcji

SELECT

. W

podanym przykładzie wykorzystaliśmy tabelę

CUSTOMER. Funkcja

MaxInt

będzie wykonywana dla każdego wiersza tabeli,

więc uruchamiając podany kod możemy otrzymać wielokrotnie powtarzaną
wartość.

background image

Rozdział 17 Delphi w Interbase

537

WSKAZÓWKA

Możemy utworzyć jednowierszową tabelę InterBase, którą wykorzystamy do
tworzenia zapytań nie odnoszących się do tabel. Tabela taka może być
wykorzystana w instrukcji

SELECT

wtedy, gdy praktycznie nie korzystamy

z danych z żadnej tabeli. Oto przykład utworzenia i użycia takiej tabeli (każde
polecenie należy wykonać osobno w WISQL):

CREATE TABLE DUAL
(A CHAR(1));
INSERT INTO DUAL (A) VALUES ('A');

SELECT 22/7 AS ApproximatePI
FROM DUAL;

Deklarację zewnętrznej funkcji można usunąć z bazy za pomocą instrukcji

DROP

EXTERNAL FUNCTION.

Kursory (Cursors)

Koncepcja kursorów jest wynikiem zastosowania zorientowanej na zbiory
koncepcji SQL w odniesieniu do przetwarzania wierszowego. Pozwalają one
pracować z jednym wierszem w danej chwili. Ponieważ ich tworzenie i obsługa
jest w BDE zautomatyzowana, więc w zasadzie nie ma potrzeby tworzenia
własnych kursorów. Jednak niekiedy mogą się one okazać użyteczne
w procedurach pamiętanych.

Są cztery podstawowe operacje wykonywane na kursorze: deklarowanie (ang.
declare), otwarcie (ang. open), pobranie (ang. fetch), zamknięcie (ang. close).
Można go też wykorzystać do zmodyfikowania lub usunięcia pojedynczego
wiersza tabeli.

UWAGA

Nie można wykonywać tych instrukcji samodzielnie w programie WISQL. Są one
przeznaczone do użycia tylko w procedurach pamiętanych.

Deklaracja kursora składa się z

instrukcji

SELECT

i

(dla kursorów

modyfikowalnych) - z listy modyfikowalnych kolumn. Oto przykład:

DECLARE CUSTOMER_SELECT CURSOR
FOR SELECT * FROM CUSTOMER

Zanim uzyskamy dostęp do wierszy przy użyciu kursora, musi on być najpierw
otwarty. Aby przygotować zapytanie zapisane w definicji kursora należy użyć
instrukcji

OPEN

:

background image

538

Część III

OPEN CUSTOMER_

SELECT

Samo

OPEN

nie wprowadza jednak wierszy do aplikacji klienta. Niezbędna jest

instrukcja

FETCH

:

FETCH CUSTOMER_SELECT

W ten sposób otrzymamy jeden wiersz ze zbioru wynikowego kursora. Każde
następne

FETCH

pozwala uzyskać następny wiersz w zbiorze. InterBase posiada

tylko kursory jednokierunkowe. Aby przejść do wierszy poprzednich należy
zamknąć (

CLOSE

) i ponownie otworzyć (

OPEN

) kursor.

UWAGA

Mimo że InterBase nie obsługuje kursorów dwukierunkowych, można ich użyć
w aplikacji stworzonej w Delphi. BDE emuluje bowiem dwukierunkowy kursor na
poziomie programowym - bez względu na to, czy serwer baz danych go obsługuje.
Dlatego można przewijać w obie strony w obiektach

TDataSets

takich jak

TQuery i TTable

.

Wiersze zwracane przez modyfikowalny kursor mogą być zmieniane za pomocą
specjalnych wersji instrukcji

UPDATE i DELETE

jak np.:

DECLARE CUSTOMER_UPDATE CURSOR
FOR SELECT *FROM CUSTOMER
FOR UPDATE OF LastName

UWAGA

Należy się upewnić, czy na liście kolumn klauzuli

FOR UPDATE OF

umieszczono tylko te kolumny, które mają być rzeczywiście aktualizowane.
Umieszczenie na tej liście innych pól niepotrzebnie wiąże zasoby serwera.

Aby zmodyfikować lub usunąć bieżący wiersz modyfikowalnego kursora, należy
posłużyć się wyrażeniem

WHERE CURRENT OF

cursorname

, jak to pokazano

w poniższym przykładzie:

UPDATE CUSTOMER
SET LastName="Cane"
WHERE CURRENT OF CUSTOMER_UPDATE

lub:

DELETE FROM CURSOR
WHERE CURRENT OF CUSTOMER_UPDATE

background image

Rozdział 17 Delphi w Interbase

539

Gdy kończymy pracę z kursorem należy go zamknąć (instrukcją

CLOSE)

.

Zamknięcie kursora zwalnia wszystkie zasoby systemowe, których używał. Oto
przykład:

CLOSE CUSTOMER_UPDATE

Administrowanie bazą Interbase

Zwykle osoby tworzące bazy danych wykonują tylko najprostsze czynności
administracyjne. W naszych rozważaniach ograniczymy się do podstawowych,
niezbędnych narzędzi administrowania bazą. Oczywiście skomplikowane
problemy najlepiej pozostawić do rozwiązania administratorom bazy danych.

Archiwizacja i odzyskiwanie danych

Podstawową troską projektantów, administratorów i użytkowników baz danych
jest bezpieczeństwo danych. Musimy więc przede wszystkim zabezpieczyć bazę na
wypadek uszkodzenia dysków, na których jest umieszczona. W tym celu tworzymy
kopie bazy danych. Nie wystarczy jednak po prostu skopiować pliki z danymi.
Część z nich może być bowiem akurat w użyciu i znajdować się częściowo
w pamięci serwera. Dlatego zwykła kopia, sporządzona narzędziami systemu
operacyjnego, nie daje prawdziwego obrazu stanu bazy w danym momencie i nie
gwarantuje jej spójności. Dopiero Server Manager zapewni nam właściwą
archiwizację danych. Postępujemy następująco :

1. Uruchamiamy program Server Manager

2. Klikamy

File\Server Login

i łączymy się z serwerem.

3. Wybieramy

Tasks\Backup

- aby wyświetlić okno dialogowe do archwizacji

4. W lini

Database Path

wpisujemy pełną ścieżkę dostępu do danych, które

chcemy archiwizować. Gdy archiwizujemy odległą bazę na platformie innej niż
NetWare, wybieramy

Remote

.

5. Wpisujemy nazwę pliku lub urządzenia, którego chcemy użyć, w linii

Backup

File or

Device

. W Windows NT można wpisać domyślne urządzenie taśmowe

jako

\\.\tape0

.

6. Aby rozpocząć archiwizację klikamy

OK

. Sytuację ilustruje rys 17.1.

Odzyskiwanie zarchiwizowanych danych jest po prostu odwróceniem poprzednio
opisanego procesu. Wybieramy opcję

Restore

z menu

Tasks

, określając swoją

kopię jako

Restore Source

, a swoją bazę jako

Restore Destination

background image

540

Część III

Zarządzanie kontami użytkowników

Aby móc łączyć się z bazą danych, trzeba być zarejestrowanym jako użytkownik
i znać swoje hasło. Do utworzenia konta nowego użytkownika można użyć
polecenia

Task\User Security

z menu programu Server Manager. Postępujemy

wtedy zgodnie z poniższą procedurą:

1. Uruchamiamy program Serwer Manager.

2. Klikamy

File\Sever Login

i łączymy się z serwerem

3. Wybieramy

Tasks\User Security

, aby wyświetlić okienko dialogowe InterBase

Security.

4. Klikamy przycisk

Add User

.

5. Wprowadzamy nazwę i hasło dla nowego użytkownika.

6. Klikamy

OK

, aby dodać nowego użytkownika. Ilustruje to rysunek 17.2

Rysunek 17.1
Wykorzystanie
Server Managera
do archiwizacji
bazy danych

Rysunek 17.2
Dodawanie nowego
uzytkownika
InterBase
w programie Server
Manger. Okno
dialogowe User
Configuration

background image

Rozdział 17 Delphi w Interbase

541

Po utworzeniu konta użytkownika możemy się łączyć z dowolną bazą danych
InterBase’a. Jednak korzystanie z bazy jest możliwe dopiero po nadaniu praw
dostępu do poszczególnych obiektów bazy.

Konfiguracja serwera

Jest parę sposobów dojścia do okna dialogowego

Interbase Server Configuration

.

Umożliwia to Server Manager poleceniem

Config

z menu

Task\Server

. Możemy

też kliknąć prawym przyciskiem myszy ikonę

InterBase Server

na pasku zadań

Windows i wybrać polecenie

Properties

.

W oknie dialogowym

Server Configuration

parametry serwera InterBase zostały

podzielone na dwie klasy: IB (InterBase) Settings i OS (Operating system)
Settings. Ustawienia IB składają się z dwóch parametrów:

Database Cache

i

Client map size

.

Database cache

określa liczbę stron

zarezerwowanych na pamięć cache dla baz. W zasadzie wszystkie bazy można by
umieścić w pamięci RAM, jeśli cache będzie odpowiednio duży. Przyspieszyłoby
to znacznie wszelkie operacje na bazie. Jednak ustalając zbyt duży cache
w stosunku do zasobów komputera powodujemy, że system operacyjny przenosi
część pamięci cache na dysk, zmniejszając w ten sposób wydajność serwera.

Client map size

określa rozmiar bufora rezerwowanego dla każdego

połączonego z bazą klienta. Zwykle nie ma potrzeby zmieniania tego parametru -
można go zwiększyć przy transmisjach dużych porcji danych (np. BLOB) do i
z aplikacji klienta.

Ustawienia OS zawierają trzy pozycje:

Min Process Working Set

,

Max Process

working

Set

i

Process

Priority

Class

.

Min

i

Max Process working Set

kontrolują

wielkość oddanej do dyspozycji serwera bazy danych pamięci fizycznej.
Podwyższając wartość maksymalną pozwalamy na zwiększenie ustawień Database
Cache, jednak zbyt duża wartość tego parametru może powodować błędy
stronnicowania (ang. page faults). W Windows NT można sprawdzić - poprzez NT
Performance Monitor - czy parametry pracy serwera wymagają korekty. Aby
określić, czy ustawienia

Min

i

Max

process

Working

Set

są właściwe, wykonujemy

następujące kroki:

1. Jeśli InterBase server jest już uruchomiony, włączamy program NT

Performance Monitor (najlepiej na tym samym komputerze)

2. Wybieramy nowy wykres i naciskamy CTRL+I - aby dodać nowy licznik do

wykresu.

3. Wybieramy

Object Process, Instance

:

IBSERVER, Counter:Page File Bytes

i klikamy

Add

.

4. Dodajemy licznik dla

IBSERVER

Page

faults/sec

i

% Processor

Time

. (patrz

rysunek 17.3)

background image

542

Część III

Jeśli stwierdzimy dużą ilość błędów stronicowania (Page Faults) lub % Processor
Time jest mniejszy niż 50%, można zwiększyć zakres Process Working Set, co
powinno poprawić wydajność serwera. Wprowadzone zmiany zostaną
uwzględnione przy następnym starcie serwera.

Process Priority Class określa priorytet procesów inicjowanych przez serwer
InterBase wśród innych procesów aktualnie uruchomionych na komputerze
serwera. Zmieniając priorytet na High można uzyskać znaczny wzrost wydajności
- szczególnie na komputerach wydzielonych (ang. dedicated) wyłącznie do pracy
z serwerem InterBase, oraz w sytuacjach, gdy duża ilość aplikacji jest aktywna na
komputerze serwera. Zmiany tego ustawienia realizowane są natychmiast po
kliknięciu

Apply

.

Przeglądanie statystyki blokad

Systemy klient/serwer wykorzystują pesymistyczny mechanizm sterowania
współbieżnością, więc są wyposażane w różnorodne narzędzia obsługujące
blokady i rywalizację o dostęp. InterBase, jak większość wielodostępnych DBMS,
odpowiednio blokuje zasoby - aby zapobiec jednoczesnemu, niekontrolowanemu
procesowi wprowadzania zmian przez wielu użytkowników. Oczywiście niezbędne
są narzędzia do kontrolowania i

usuwania problemów związanych

z wielodostępem. Blokady zakładane przez serwer InterBase’a można obejrzeć
wybierając polecenie

Tasks\Lock Manager Statistics

w programie Server Manager

(patrz rysunek 17.4).

Rysunek 17.3
Użycie NT
Performabce
Monitor do
określenia potrzeb
serwera
InterBaze’a
w zakresie RAM.

background image

Rozdział 17 Delphi w Interbase

543

Program zarządzający blokadami w InterBase korzysta ze specjalnej tablicy do ich
śledzenia. Są w

niej informacje na temat statusu wszystkich blokad.

LOCK_HEADER BLOCK podaje szeroki zakres danych podsumowujących - jak
np. aktualny i maksymalny rozmiar zablokowanych tablic, liczbę zakleszczeń itp.
W części szczegółowej dotyczącej poszczególnych procesów możemy sprawdzić,
który proces zarządził daną blokadę, które blokady zostały zwolnione, a które
czekają itd. Wszystkie te informacje mogą się okazać pomocne w rozwiązywaniu
problemów związanych z blokadami, jak np. zakleszczenie (ang. deadlock)

Sprawdzanie integralnośći bazy

Oprócz regularnej archiwizacji danych należy - dla zapewnienia sobie
wiarygodności danych w bazie - podjąć inne środki. Powinno się regularnie
sprawdzać ich poprawność, najlepiej bezpośrednio przed lub po dokonaniu
archiwizacji. Umo¿liwia to polecenie menu

Maintance\Database Validation

w InterBase Server Manager. Rysunek 17.5 pokazuje okno dialogowe

Database

Validation

.

Database Validation wykonuje trzy podstawowe funkcje: inwentaryzuje
uszkodzone struktury na dysku, pokazuje strony z błędną alokacją i zwalnia
miejsce na dysku po "osieroconych" stronach. Standardowo korekty w strukturze,

RYSUNEK 17.4
Okno Lock
Manager Statistics
wyświetla ważne
informacje
dotyczące blokad
InterBase.

Rysunek 17.5
Sprawdzanie bazy -
okienko dialogowe
Database
Validation

background image

544

Część III

które nie dotyczą danych użytkownika wykonywane są automatycznie. Można
jednak zablokować przeprowadzanie zmian przez wybranie opcji

Read-only

validation

.

Każdy błąd wykryty przez program sprawdzający wyświetlany jest w okienku. Po
kliknięciu przycisku

Repair

program podejmie próbę ich naprawy. Program

sprawdzający może także warunkowo pomijać wykryty błąd sumy kontrolnej. Aby
naprawić uszkodzoną bazę wykonujemy kroki opisane poniżej

1. Kopiujemy bazę z pominięciem programu ServerManager Backup. Można użyć

zwykłego polecenia

Copy

albo Eksploratora Windows. Oprogramowanie

InterBase nie archiwizuje bowiem uszkodzonych baz.

2. Dla sprawdzenia uszkodzeń w bazie wybieramy polecenie

Maintenance\

Database

Validation

.

3. Po zakończeniu weryfikacji klikamy przycisk

Repair

- aby zaznaczyć lub

naprawić uszkodzone struktury

4. Jeśli powstały błędy sumy kontrolnej ponownie wybieramy polecenie

Database

Validation

, tym razem jednak z opcją

Ignore checksum errors

ustawioną na

TRUE

.

5. Kiedy proces się zakończy klikamy

Repair

- aby naprawić nowo wykryte

uszkodzenia.

6. Uruchamiamy Database Validation, wybierając tym razem opcję

Read

-

only

validation

. Warto zwrócić uwagę na fakt, że zwolnione stronice nie są już

wyświetlane, a niepełne rekordy zaznaczone jako uszkodzone. Każdy rekord
zaznaczony jako uszkodzony nie będzie archiwizowany przez program Backup
z Server Managera.

7. Archiwizujemy naprawioną bazę programem archiwującym z Server Managera.

Uszkodzone rekordy zostaną oczywiście wyłączone z archiwizacji.

8. Odzyskujemy zarchiwizowaną bazę. Ta operacja pozwoli na przebudowanie

pewnych struktur wewnętrznych i usunięcie uszkodzonych części z bazy.

9. Uruchamiamy Database Validation po raz ostatni - aby sprawdzić, czy

rzeczywiście baza została naprawiona. Tym razem wybieramy opcję

Read

-

only

validation

.

Statystyki bazy danych

Opisywane tutaj polecenia Server Managera wymagają aktywnego połączenia
z daną bazą. Musimy być więc zarejestrowani na serwerze oraz połączeni z bazą
(polecenie

File\Database Connect

w Server Manager).

background image

Rozdział 17 Delphi w Interbase

545

Polecenie

Task\Database Statistics

wyświetla różnorodne informacje odnoszące

się do bazy. Są wśród nich między innymi: data utworzenia bazy, najstarsza
aktywna transakcja, rozmiar strony, liczba zdefiniowanych cieni. Niektóre z tych
danych są także dostępne poprzez polecenia

Maintance\Database Properties

.

Rysunek 17.6 pokazuje okno utworzone przez

Database

Statistics

.

Gdy okno

Database Statistics

jest na ekranie, można wybrać polecenie

Database

Analysis

z menu

View

- aby zobaczyć ilość stron alokowanych dla bazy i ich

wypełnienie. Ułatwi to nam zrozumienie, jak struktura logiczna bazy wpływa na
fizyczne rozmieszczenie danych.

Czyszczenie bazy (Database sweeping)

Polecenie

Maintenance\Database Sweep

zwalnia miejsce po starych wersjach

rekordów z odrzuconych transakcji. Chociaż nie jest to niezbędne, należy zamknąć
bazę na czas jej oczyszczenia - ze względu na wpływ tej operacji na działanie
programów użytkowników. Oczyszczanie dużych baz może bowiem drastycznie
spowolnić realizację innych procesów.

Odzyskiwanie transakcji (Transaction Recovery)

Każda transakcja, obejmująca zakresem wiele baz, jest w InterBase zatwierdzana
dwufazowo. Zapewnia to zachowanie niepodzielności transakcji dla wszystkich
baz składowych. Dwufazowe zatwierdzanie może się nie udać ze względu na
zerwanie połączenia sieciowego lub awarii dysku, która uniemożliwi dostęp do
części baz. Polecenie

Maintaince\Transaction Recovery

ma za zadanie obsługę

transakcji pozostających w „zawieszeniu” po nieudanym procesie dwufazowego
zatwierdzania. Pozwala ono odzyskać te transakcje i - w zależności od sytuacji -
wycofać lub zatwierdzić.

Rysunek 17.6
Okno Database
Statistics
z podstawowymi
informacjami
o bazie.


Wyszukiwarka

Podobne podstrony:
18 rozdzial 17 obddadd7lgo54zmd Nieznany (2)
18 rozdzial 17 vmtc3jege7kyyouu Nieznany (2)
18 Rozdział 17
17 rozdzial 16 fq3zy7m2bu2oan6t Nieznany (2)
17 18 GPW102 Rocznik2012 Miedzy Nieznany (2)
Cw 17 18 Energia wiatru ver1 1 Nieznany
17 rozdzial 16 yvfz6z3wpvhesr3l Nieznany
17 rozdzial 16 TPJAM3FHUOB6YWBN Nieznany (2)
17 rozdzial 16 fq3zy7m2bu2oan6t Nieznany (2)
17 18 GPW102 Rocznik2012 Miedzy Nieznany (2)
Rozdział 17, 18
FIY Rozdział 17, 18
18 FALA TETNAid 17717 Nieznany (2)
05 rozdzial 04 nzig3du5fdy5tkt5 Nieznany (2)
28 rozdzial 27 vmxgkzibmm3xcof4 Nieznany (2)
22 Rozdzial 21 KP4Q5YBIEV5DBSVC Nieznany (2)
09 08 Rozdzielnice budowlane RB Nieznany (2)
Kanicki Systemy Rozdzial 10 id Nieznany

więcej podobnych podstron