Axel Kohnert
Lehrstuhl Mathematik 2
WS 2000/2001
SQL wurde Ende der 70er Jahre
von IBM entwickelt. Es war als Abfragesprache zur IBM Datenbank DB2 vorgesehen.
DB2 ist eine relationale Datenbank die auch heute noch vertrieben wird.
SQL ist eine Abkürzung für
structured query language
Später wurde SQL von
der Organisation ANSI standardisiert. Aber fast alle Datenbankanbieter
implementieren eine Obermenge, d.h. sie bieten Erweiterungen an. Der aktuelle
Standard ist SQL92. SQL wurde für eine relationale Datenbank
geschrieben. Der Erfolg dieser Datenbanken ist auch der Grund dafür,
dass SQL der de facto Industriestandard ist.
Mit SQL werden sowohl die
'normalen' Datenbankoperationen
·Einfügen
·Löschen
·Suchen
·Anlegen von Tabellen
·Löschen
von Tabellen
als auch Aufgaben des Administrators
·Datenbanken anlegen
·Benutzerrechte manipulieren
·Benutzer anlegen/löschen
·Systemsicherheit
gewährleisten
erledigt.
Dies ist der Befehl um Daten in der Datenbank zu suchen. Die select Anweisung hat folgende Form
SELECT ... FROM ..........
Die Worte
select und from sind Schlüsselworte die vorkommen müssen. Bei
Schlüsselworten wird nicht zwischen Groß- und Kleinschreibung
unterschieden. Man erkennt auch den Ansatz die Anfrage möglichst natürlichsprachlich
zu formulieren. In einer relationalen Datenbank werden alle Daten in Tabellen
gehalten. Für unsere Beispiele nehmen wir eine online Buchhandlung.
Es gibt folgende Tabelle mit Namen BOOKS
SELECT
* FROM BOOKS;
und man
erhält die Tabelle inklusive der Kopfzeile mit den Spaltennamen als
Ergebnis. Der Strichpunkt dient als Abschluss des SQL Befehls. Die erste
Variante ist der Fall, dass man nicht alle Spalten der Tabelle haben will,
weil man z. B. mit der ISBN Nummer und der Verlags id nichts anfangen kann.
Der Befehl lautet dann:
SELECT
AUTOR,TITLE FROM BOOKS; und man
erhält die 2 spaltige Tabelle
SELECT PRICE FROM BOOKS;
erhält man die Ausgabe:
DISTINCT
umgehen. Mit der Abfrage
SELECT DISTINCT PRICE FROM BOOKS;
erhält man die Ausgabe:
SELECT AUTOR, TITLE, PRICE, PRICE*2.20
FROM BOOKS;
Mit der
WHERE Klausel werden Zeilen ausgewählt. Das Konstrukt wirkt als eine
Art Filter. Zuerst ein einfaches Beispiel
SELECT
AUTOR, TITLE, PRICE FROM BOOKS WHERE PRICE >30;
Folgende Vergleichsoperatoren stehen zur
Verfügung: = Gleichheit
Das funktioniert nicht nur bei numerischen
Einträgen sondern auch beim Datum und Zeichenketten. Natürlich
können auch wieder logische Bedingungen aus der Verknüpfung von
mehreren Spalten formuliert werden. Es gibt noch weitere Verknüpfungsoperatoren
LIKE
Dies dient zur Auswahl mittels regulärer
Ausdrücke. Ausgewählt wird, wenn der Zeichenketteneintrag matcht.
Mit dem Befehl
SELECT ISBN, AUTOR, PRICE FROM BOOKS
WHERE AUTOR LIKE '%R%';
BETWEEN
Dient zur Auswahl von Intervallen.
SELECT ISBN, AUTOR, PRICE FROM BOOKS
WHERE PRICE BETWEEN 35 AND 45;
Damit wird getestet ob ein Wert innerhalb
einer gegebenen Wertemenge liegt.
SELECT
AUTOR, TITLE, PRICE FROM BOOKS WHERE PRICE IN (32,"39,95");
AND, OR, NOT
kann man auch kompliziertere Bedingungen
aufbauen:
SELECT AUTOR, TITLE, PRICE FROM BOOKS
WHERE AUTOR LIKE '%R%' AND PRICE BETWEEN 25 AND 35;
Bei der select Anweisung können auch
Funktionen angegeben werden, die auf die Ergebniszeilen angewandt werden:
SELECT AVG(PRICE) FROM BOOKS;
Das Ergebnis ist der Durchschnittswert
über alle Einträge in der PRICE Spalte der BOOKS Tabelle. Weitere
Funktionen sind
COUNT()
das ist die Anzahl der Einträge
und verschiedene weitere, meist statistische
Funktionen, als eigene Erweiterungen der verschiedenen Datenbankanbieter.
Diese Funktionen können verknüpft werden mit dem WHERE Schlüsselwort:
SELECT AVG(PRICE) FROM BOOKS WHERE AUTOR='Goethe';
oder um z. B. die Anzahl der verschiedenen
Autoren in der Datenbank zu bestimmen verwendet man das DISTINCT Schlüsselwort.
SELECT COUNT(DISTINCT AUTOR) FROM BOOKS;
GROUP BY
Bisher wurden die Funktionen auf das Gesamtergebnis
der Auswahl angewandt, dies ändert sich mit der GROUP BY Anweisung:
SELECT AUTOR,AVG(PRICE) FROM BOOKS GROUP
BY AUTOR;
Damit wird für jeden Autor eine Zeile
mit dem Namen und dem Durchschnittspreis seiner Bücher ausgegeben.
Will man derartige Anfragen formulieren muss man darauf achten, dass nur
solche Spalten ausgewählt werden die für alle Zeilen die mittels
GROUP BY zusammengefasst werden den gleichen Eintrag haben. Falsch wäre
z. B.
SELECT AUTOR,ISBN,AVG(PRICE) FROM BOOKS
GROUP BY AUTOR;
da der Fall passieren kann dass, ein Autor
Bücher mit verschiedenen ISBN Nummern hat.
HAVING
Das ist das Schlüsselwort, wenn man
Eigenschaften von Blöcken, die mit GROUP BY zusammengefasst wurden,
finden will. So z.B. alle Autoren, deren Durchschnittspreis über 100
liegt:
SELECT AUTOR,AVG(PRICE) FROM BOOKS GROUP
BY AUTOR HAVING AVG(PRICE)>100;
Der Unterschied zum WHERE Schlüsselwort
ist die Anwendung auf die Blöcke geformt durch GROUP BY im Gegensatz
zu der einzelnen Zeile wie es beim WHERE Schlüsselwort passiert. Das
macht keinen Unterschied, wenn als Auswahlkriterium keine zusammenfassende
Funktion genommen wird:
SELECT AUTOR,AVG(PRICE),PUBLISHER_ID
FROM BOOKS GROUP BY AUTOR,PUBLISHER_ID HAVING PUBLISHER_ID='AW';
oder aber
SELECT AUTOR,AVG(PRICE),PUBLISHER_ID
FROM BOOKS WHERE PUBLISHER_ID='AW' GROUP BY AUTOR,PUBLISHER_ID;
In beiden Fällen wird der Durchschnittspreis
für die Bücher eines Autors beim AW Verlag ermittelt. Im ersten
Fall wird der AW Verlag am Ende herausgefiltert, im zweiten Fall, bevor
die Gruppen zusammengefasst werden.
und beim Autor wird die ansteigende lexikographische
Ordnung genommen (ASC ist default und eigentlich überflüssig)
und innerhalb der Bücher vom gleichen Autor erscheint das teuerste
zuerst. Eine andere Möglichkeit ist statt des Namen die Position der
Spalte zu verwenden:
SELECT * FROM BOOKS ORDER BY 5 DESC;
und es wird wieder nach dem Preis sortiert,
diesmal kommt das teuerste Buch zuerst.
Um das Buch nachzubestellen braucht er
die Verlagsanschrift, und da diese für alle Bücher des gleichen
Verlags gleich ist hat sie ein guter Datenbankdesigner in einer eigenen
Tabelle PUBLISHER abgelegt, und dort findet der Buchhändler:
und mit der Abfrage
SELECT * FROM BOOKS,PUBLISHER
WHERE BOOKS.PUBLISHER_ID=PUBLISHER.PUBLISHER_ID AND TITLE = 'Programming
in SQL';
erhält der Buchhändler alle Daten
zur Nachbestellung. Es wurden die zwei Tabellen über das gemeinsame
Attribut PUBLISHER_ID verschmnolzen, und eine neue Tabelle entstand, aus
der wurde dann eine Zeile herausgewählt. Theoretisch (relationale
Datenbanktheorie) hat die Tabelle nach dem Join folgende Spalten:
Intern wird bei der Abfrage (wie man auch
an der Syntax erkennt) ein direktes Produkt gebildet und dann herausgefiltert.
Die verwendete Verknüpfung war der sogenannte Equi-Join da die Verschmelzung
mit der Gleichheit BOOKS.PUBLISHER_ID = PUBLISHER.PUBLISHER_ID geschah.
Als ein weiteres Beispiel noch eine Abfrage um den Durchschnittspreis
je Land des Verlags herauszubekommen:
SELECT PUBLISHER.LAND HERKUNFTSLAND,
AVG(PRICE) DURCHSCHNITTSPREIS FROM BOOKS,PUBLISHER GROUP BY PUBLISHER.LAND;
und an diesem Beispiel wurde auch noch
die Verwendung von Aliasnamen bei den Spaltenüberschriften gezeigt.
Eine weitere Verwendung des Joins ergibt sich beim sogenannten Auto-join,
d.h. der Join einer Tabelle mit sich selbst:
SELECT x.TITLE FROM BOOKS x, BOOKS y
WHERE y.TITLE='Programming in SQL' AND x.TITLE LIKE '%SQL%' AND x.PRICE
< y.PRICE
damit kann man Bücher über SQL
finden, die billiger sind als das Buch Programming in SQL. Man kann die
SQL Befehle in drei Gruppen einteilen:
Um etwas aus einer Tabelle auszuwählen
muss diese natürlich zuvor erzeugt werden. Die zugehörigen
Befehle fallen in den Teil der Data Description Language (Erzeugen) . Zum
Erzeugen einer Tabelle dient der Befehl
CREATE TABLE
Um obige Beispieltabelle BOOKS zu erzeugen
wäre folgender Aufruf passend:
CREATE TABLE BOOKS (ISBN CHAR(13), AUTOR
CHAR(100), TITLE CHAR(200), PUBLISHER_ID CHAR(10), PRICE NUMBER(7,2));
Nach den Schlüsselwörtern kommt
der Name der Tabelle, danach die Attributnamen zusammen mit dem Attributtyp
getrennt durch Kommata. Die Datentypen variieren leicht von Anbieter zu
Anbieter. Obige Syntax funktioniert bei Oracle. Die Typen bedeuten folgendes:
Beim Erzeugen einer Tabelle kann man zusätzliche
Bedingungen formulieren, z.B. dass ein Eintrag vorhanden sein muss. So
erzeugt der Befehl
CREATE TABLE BOOKS (ISBN CHAR(13) NOT
NULL , AUTOR CHAR(100), TITLE CHAR(200), PUBLISHER_ID CHAR(10), PRICE NUMBER(7,2));
die gleiche Tabelle mit der Nebenbedingung,
dass stets ein Eintrag in der Spalte ISBN vorhanden sein muss. Dies wird
beim Einfügen oder Ändern überprüft. Bei Schlüsseln
(später) sollte dies verlangt werden. Ferner können weitere Bedingungen
angegeben werden, die dann beim Einfügen / Ändern überprüft
werden. Will man z.B. keine Bücher für unter 2$ verkaufen, so
kann man das Einfügen / Ändern mit dem folgenden Befehl
verhindern:
CREATE TABLE BOOKS (ISBN CHAR(13)
, AUTOR CHAR(100), TITLE CHAR(200), PUBLISHER_ID CHAR(10), PRICE NUMBER(7,2)
CHECK (PRICE > 2) );
Um die Tabelle wieder zu Löschen gibt
es den Befehl
DROP TABLE
und im Beispiel kann die Tabelle mit
DROP TABLE BOOKS;
wieder gelöscht werden. Die andere
Möglichkeit ist das Ändern einer bestehenden Tabelle das passende
Schlüsselwort ist
ALTER TABLE
es ist nicht in allen SQL Varianten verfügbar,
aber z.B. in Oracle. Es gibt zwei Varianten
ALTER TABLE .... ADD ...
ALTER TABLE .... MODIFY .....
um z.B. in die BOOKS Tabelle noch eine
Spalte mit der Anzahl der verkauften Exemplare einzufügen:
ALTER TABLE BOOKS ADD (NUMBERS INTEGER);
und die Einträge werden mit dem sog.
NULL Wert vorbesetzt. Eine nachfolgende Abfrage liefert das Ergebnis:
SELECT * FROM BOOKS WHERE TITLE LIKE
'%SQL%';
Eine Spalte mit dem Modifier NOT NULL kann
nur zu einer leeren Tabelle hinzugefügt werden. Eine weitere Variante
ist das Erzeugen einer neuen Tabelle aus dem Ergebnis einer SELECT Anweisung,
damit wird eine neue Tabelle erzeugt und sofort mit dem Ergebnis der SELECT
Anweisung gefüllt.
CREATE TABLE SQLBOOKS AS SELECT * FROM
BOOKS WHERE TITLE LIKE '%SQL%';
und die neue Tabelle SQLBOOKS hat die gleichen
Spalten wie die Tabelle BOOKS und enthält alle Bücher aus der
Tabelle BOOKS in der deren Titel das Wort SQL vorkommt. Ein nachfolgendes
SELECT * FROM SQLBOOKS;
Mit dem CREATE Befehl wird eine neue
Tabelle als Kopie angelegt, d.h. spätere Änderungen an BOOKS
werden nicht automatisch übernommen. Anders ist das bei VIEWS (später).
Der nächste Schritt ist das Füllen
der Tabelle mit Einträgen. Diese Befehle fallen in den Bereich
der Data Manipulation Language. Beim Einfügen werden komplette
Zeilen angegeben. Die Schlüsselwörter hierzu sind:
INSERT INTO ... VALUES
Im Beispiel
INSERT INTO BOOKS VALUES ('0-7895-0052-3','Rob
Coronel','Database Systems','bd_fr',29.95);
wobei die Hochkommata nötig sind zur
Eingabe der Zeichenketten. Ferner ist zu beachten, dass der Preis mit einem
Punkt zur Trennung von Vorkomma und Nachkommateil eingegeben wird. Dies
Beispiel betrifft auch die noch nicht um die Spalte NUMBER erweiteret Tabelle.
Will man nicht alle Werte eingeben, was erlaubt ist wenn nicht der Modifier
NOT NULL verwendet wurde muss man folgende Syntax verwenden:
INSERT INTO BOOKS (TITLE) VALUES
('Informatik Band 3');
und damit wird eine Zeile eingefügt
die nur in der Spalte TITEL einen Eintrag enthält. Im Falle, dass
eine der übrigen Spalten als NOT NULL angegeben wurde verursacht eine
derartige Anweisung einen Fehler. Will man Löschen so geschieht das
ähnlich dem SELECT mit der Anweisung
DELETE FROM .... WHERE ....
bzw. ohne WHERE, wobei die gesamten Tabelleneinträge
gelöscht werden. Will man z.B. obiges Einfügen wieder Löschen:
DELETE FROM BOOKS WHERE TITLE='Informatik
Band 3';
Oder man kann alle Zeilen Löschen,
in der z.B. der PRICE nicht gesetzt ist:
DELETE FROM BOOKS WHERE PRICE IS NULL;
Eine andere Möglichkeit ist, die fehlerhafte
Zeile zu ändern, dazu gibt es das Schlüssselwort
UPDATE .... SET .... WHERE
und mittels WHERE wird die Zeile (oder
Teiltabelle ausgewählt) und mit SET werden die Spalteneinträge
geändert:
UPDATE BOOKS SET ISBN='3-446-18699-9'
AUTOR='Christian Horn' PUBLISHER_ID='Hanser' PRICE='22' WHERE TITLE='Informatik
Band 3';
und damit sind die NULL Werte ersetzt worden.
Eine andere Anwendung der UPDATE Anweisung ist z.B. eine Preiserhöhung
des Hanser Verlags:
UPDATE BOOKS SET PRICE=PRICE*1.07 WHERE
PUBLISHER_ID='Hanser';
und der Preis aller Bücher, die im
Hanser Verlag erscheinen werden 7% teurer.
CREATE VIEW
angelegt. Danach kann mit diesem View genauso
wie mit einer realen Tabelle gearbeitet werden. Lediglich beim schreibenden
Zugriff gibt es
Auch das Definieren von Sichten fällt
in den Bereich der Data Definition Language. Um z.B. die Tabelle mit den
SQL Büchern anzulegen
CREATE VIEW SQLBOOKS AS SELECT * FROM
BOOKS WHERE TITLE LIKE '%SQL%';
Der Unterschied zum CREATE TABLE AS ist,
dass damit nur eine neue Sicht definiert wird, d.h. alle nachfolgenden
Änderungen in der Tabelle BOOKS werden übernommen, da bei jedem
Zugriff auf SQLBOOKS die darunter liegende Abfrage neu ausgewertet wird.
Nachfolgend kann auch in einen VIEW eingefügt werden, die geschieht
mit dem normalen INSERT Befehl
INSERT INTO SQLBOOKS VALUES ('0-7895-0052-3','Rob
Coronel','Database Systems','bd_fr',29.95);
und ein nachfolgendes SELECT auf diese
Zeile bringt eine Fehlermeldung, denn der Titel matcht nicht auf die VIEW
Bedingung. Um schon beim INSERT die Fehlermeldung zu bekommen muss bei
der VIEWS Definition die Option
WITH CHECK OPTION
angegeben werden. Werden bei der Sicht
nicht alle zugrundeliegenden Spalten verwendet, so werden diese beim Einfügen
mit NULL Werten besetzt.
CREATE VIEW SQLBOOKS AS SELECT * FROM
BOOKS WHERE TITLE LIKE '%SQL%' WITH CHECK OPTION ;
Das Löschen einer Sicht geschieht
mit dem Befehl
DROP VIEW ...
wie das Löschen von Tabellen. Beim
Definieren von VIEWS kann man sich neue Spalten Namen definieren:
CREATE VIEW SQLSHORTLIST (SQLTITEL,
AUTOR, VERLAG) AS SELECT BOOKS.TITLE, BOOKS.AUTOR, PUBLISHER.NAME FROM
BOOKS, PUBLISHER WHERE BOOKS.PUBLISHER_ID = PUBLISHER.PUBLISHER_ID;
und natürlich können VIEWS geschachtelt
werden, d.h. bei einer Definition eines VIEWS kann auf einen anderen zugegriffen
werden. Arbeitet man bei VIEWS mit Joins, so ist zu beachten, dass damit
keine Änderung an den zugrunde liegenden Tabellen möglich ist.
Ferner dürfen nur SELECT Anweisungen verwendet werden die Tabellen
als Ergebnis liefern. Zeilenorientierte SELECT Anweisungen (später)
sind nicht erlaubt.
CREATE VIEW ALLEWELT AS SELECT ISBN
, AUTOR , TITLE , PUBLISHER_ID , PRICE FROM BOOKS;
In einem zweiten Schritt wird mit
GRANT SELECT ON ALLEWELT TO WEBUSER;
dem Benutzer WEBUSER das Recht mittels
SELECT auf den VIEW ALLEWELT zuzugreifen eingeräumt. Hat der Benutzer
keine Rechte für die Tabelle BOOKS, kann so der gewünschte Schutzmechanismus
erreicht werden. Wird statt dem Benutzer das Schlüsselwort ALL verwendet,
so erhalten das Recht alle eingetragenen Benutzer. Wird das Schlüsselwort
PUBLIC verwendet so erhalten auch alle zukünfigen neu eingetragenen
Benutzer das Recht. Man kann Rechte sowohl für VIEWS als auch für
Tabellen definieren. Automatisch hat man die Rechte nach einem CREATE TABLE)
Folgende Rechte können vergeben werden (nicht vollständig)
Dann gibt es noch das Recht
GRANT UPDATE,SELECT ON ALLEWELT
TO CHEF;
Man kann das Recht auch spaltenweise definieren:
GRANT UPDATE(ISBN,AUTOR) ON ALLEWELT
TO CHEF;
Dies ist wieder abhängig von der konkreten
SQL Variante, manchmal muss man auch sagen:
GRANT UPDATE ON ALLEWELT(ISBN,AUTOR)
TO CHEF;
Es gibt noch eine Variante, mit der eine
Benutzer die gewährten Rechte weiterreichen darf, dazu dient die Erweiterung:
GRANT ... ON .. TO ... WITH GRANT
OPTION
Das Entziehen von Zugriffsrechten (sie
müssen vorher mit GRANT vergeben worden sein) passiert mit dem
Befehl
REVOKE
Die Syntax ist wie beim GRANT Kommando
REVOKE UPDATE ON ALLEWELT TO CHEF;
Man muss aufpassen (SQL Varianten abhängig)
was passiert wenn man Rechte für Gesamtviews/tabellen und einzelne
Spalten mischt und was passiert wenn man Anweisungen für PUBLIC
als auch einzelne Nutzer mischt. Eine Erweiterung wie WITH GRANT OPTION
gibt es natürlich nicht.
CREATE TABLE BOOKS (ISBN CHAR(13) NOT
NULL , AUTOR CHAR(100), TITLE CHAR(200), PUBLISHER_ID CHAR(10), PRICE NUMBER(7,2),
PRIMARY KEY (ISBN) );
und beim Einfügen wird überprüft
ob nicht ein Buch mit der gleichen ISBN schon da ist. Ferner gibt es sogenannt
Fremdschlüssel, in unserem Beispiel ist das die Spalte PUBLISHER_ID,
die in der Tabelle PUBLISHER als Schlüssel dient. Es ist klar, dass
in die Tabelle BOOKS kein Buch eingefügt werden darf, wenn nicht die
PUBLISHER_ID bereits in der Tabelle PUBLISHER vergeben ist. Dies wird durch
die folgende Definition bei CREATE TABLE erreicht:
CREATE TABLE BOOKS (ISBN CHAR(13) NOT
NULL , AUTOR CHAR(100), TITLE CHAR(200), PUBLISHER_ID CHAR(10), PRICE NUMBER(7,2),
PRIMARY KEY (ISBN) , FOREIGN KEY (PUBLISHER_ID) REFERENCES PUBLISHER(PUBLISHER_ID)
);
Die Schlüsselbedingungen können
auch direkt als Modifier zu den Spaltendefinition hinzugefügt werden:
CREATE TABLE BOOKS (ISBN CHAR(13) NOT
NULL PRIMARY KEY , AUTOR CHAR(100), TITLE CHAR(200), PUBLISHER_ID CHAR(10)
FOREIGN KEY REFERENCES PUBLISHER(PUBLISHER_ID), PRICE NUMBER(7,2)
);
was natürlich nur funktioniert wenn
der Schlüssel aus einer einzelnen Spalte besteht. Äquivalent
zu dem Schlüsselwort PRIMARY KEY kann man auch das Schlüsselwort
UNIQUE
verwenden (in beiden Varianten).Die Fremdschlüsselbedingung
definiert mit REFERENCES kann wie schon gesehen mit GRANT/REVOKE erlaubt
oder verboten werden. Ein Problem mit Fremdschlüsseln ist die Frage:
FOREIGN KEY (...) REFERENCES ... ON
DELETE SET NULL
und damit wird beim Löschen der Wert
beim Verweis auf NULL gesetzt. Ferner gibt es noch
FOREIGN KEY (...) REFERENCES ... ON
DELETE CASCADE
und in der Tabelle mit dem Verweis wird
die Zeile gelöscht. Es gibt noch die Klausel ON DELETE SET DEFAULT:
Dann wird ein sogenannter Default Wert (anstelle von NULL) gesetzt. Diesen
kann man bei der CREATE TABLE Anweisung definieren
CREATE TABLE BOOKS( ...., char(50) SPRACHE
DEFAULT 'deutsch', ..);
Das Standardverhalten ist kann auch explizit
vorgegeben werden:
FOREIGN KEY (...) REFERENCES ... ON
DELETE RESTRICT
Analog gibt es dann noch die FOREIGN KEY
Variante
FOREIGN KEY (...) REFERENCES ... ON
UPDATE ...
Schlüssel (PRIMARY KEY / UNIQUE) werden
üblicherweise vom System als Index verwandt. Dies ist eine Methode
schneller zu werden. Es wird transparent für den Benutzer ein Verzeichnis
angelegt wo die entsprechenden Daten zu finden sind. D.h. um ein Buch mit
einer gegebenen ISBN Nummer zu finden muss nicht die ganze Tabelle BOOKS
durchlaufen werden. Der Benutzer kann auch explizit einen Index anlegen
dazu gibt es den Befehl
CREATE INDEX
um z.B. schnell nach Autoren zu suchen,
legt der Designer der Datenbank einen entsprechenden Index an
CREATE INDEX AUTIND on BOOKS(AUTOR);
und ein nachfolgendes Suchen nach einen
Autor schneller werden.
SELECT AUTOR FROM BOOKS WHERE AUTOR='Dick
Francis';
Man kann auch Indices über mehrere
Spalten definieren, dann wird eine Anfrage, in der alle Spalten des Indices
vorkommen schneller. Dies ist analog der Tatsache, dass Schlüssel
über mehrere Attribut gehen können. Bei der Definition
des Index kann auch der Modfier UNIQUE verwendet werden, das bedeutet,
dass kein auf der Indexmenge identischer Datensatz eingefügt werden
kann.
CREATE UNIQUE INDEX AUTIIND ON
BOOKS(AUTOR,TITLE);
was nicht sinnvoll ist, da so jeweils nur
eine Ausgabe eines Buchs eines Autor abgespeichert werden kann. Ein PRIMARY
KEY wird automatisch als UNIQUE (man kann auch das Schlüsselwort DISTINCT
verwenden) angelegt. FOREIGN KEY werden als Indices verwandt, die
doppelte Einträge enthalten dürfen. Eine Spalte darf nicht in
mehreren Indices vorkommen. Ein Index kann nur dann zum schnellen Zugriff
auf eine Tabelle verwendet werden, wenn die bei der Suche verwendeten Spalten
in einem Index geschlossen am Anfang liegen. Im folgenden Beispiel kann
der Index zur Suche nicht verwendet werden, da für die Spalte col1
beim SELECT kein Wert angegeben wurde.
CREATE TABLE tab
CREATE INDEX idx1 ON tab (col1, col2);
SELECT * FROM tab WHERE col2 = 15;
Zum Anlegen von Indices werden meist B-Baum
Methoden verwendet. Zum Löschen eines Indexs dient der Befehl
DROP INDEX
DATABASE
Anweisung eine Datenbank auswählen,
mit der er arbeiten möchte. Bei der DATABASE Anweisung gibt es noch
den Modifier EXCLUSIVE, damit man die Datenbank als einziger nutzt. Um
z.B. bei der Buchhandlungsdatenbank nachts eine Änderung durchzuführen
kann man mit dem Befehl
DATABASE 'bookshop' EXCLUSIVE;
die Verbindung herstellen. Ein Fehler passiert
wenn ein anderer Nutzer schon eine Verbindung hat. Die einzige Alternative
ohne DATABASE Anweisung ist der Fall, dass eine neue Datenbank angelegt
wird. Dies geschieht mit der
CREATE DATABASE ....
Anweisung. Für unseren Buchladen wäre
der Befehl gewesen:
CREATE DATABASE 'bookshop';
Dies ist dann seine aktuelle Datenbank,
auf die sich alle folgenden
CLOSE DATABASE
Anweisung. Es ist nicht möglich, zwei
Datenbanken parallel zu öffnen. Zusammen mit einer Datenbank werden
verschiedene Systemfiles (data dictionary) abgespeichert. Lediglich
die Benutzer und die Datenbank (zumindest in den untersuchten Datenbanken)
sind systemweit gültige Tabellen.
CREATE TRIGGER
Anweisung. Nur der Eigentümer einer
Tabelle, sowie alle Benutzer, die über eine GRANT Anweisung
die Rechte dazu erhalten haben, dürfen einen Trigger für eine
Tabelle anlegen. Bei der Definition des Triggers wird festgelegt, welches
Ereignis einen Trigger auslöst. Mögliche Ereignisse sind:
CREATE TRIGGER log_stadt_delete AFTER
DELETE ON stadt FOR EACH STATEMENT INSERT INTO log_file VALUES(TODAY,
USER, 'AD', 'stadt');
Durch diesen Trigger wird jedesmal, wenn
eine DELETE Anweisung für die Tabelle stadt
CREATE TRIGGER tr1 AFTER UPDATE OF gehalt
ON angestellter REFERENCING NEW AS neu OLD AS alt FOR EACH ROW UPDATE abteilung
SET gehaltssumme = gehaltssumme + neu.gehalt WHERE abt_nr = alt.abt_zugeh;
Dieser Trigger erhöht automatisch
die Gesamtsumme der Gehälter einer Abteilung, wenn das Gehalt eines
Mitarbeiters der Abteilung verändert wird. Um in den ausgelösten
Aktionen auf die Daten zugreifen zu können, die in der auslösenden
Anweisung aktuell sind, wird die REFERENCING Klausel verwendet. Über
diese Klausel werden symbolische Namen für die Werte vor (OLD) bzw.
nach (NEW) der auslösenden Anweisung vergeben. Bei einem UPDATE stehen
somit die alten Werte des Datensatzes wie auch die neuen zur Verfügung.
Diese Werte sind unabhängig davon, ob der Trigger vor, statt oder
nach einer Operation ausgelöst wird. Bei einer INSERT Anweisung kann
nicht auf die alten Werte zugegriffen werden, ebenso wie bei einem DELETE
nicht auf die neuen Werte zugegriffen werden kann. Generell kann die REFERENCING
Klausel nur in FOR EACH ROW Triggern verwendet werden. In FOR EACH STATEMENT
Triggern ist dies nicht möglich.
SELECT ... FROM ... WHERE ..... (SELECT
... FROM .... WHERE)
Natürlich kann das noch weiter geschachtelt
werden. Nach der subquery kann es auch noch mit GROUP BY/HAVING/ORDER BY
weitergehen. Häufig gibt es die Möglichkeit Anfragen, die sonst
mittels Join gelöst werden auch mittels Subquerys zu lössen.
Um z.B. Bücher aus England zu finden
SELECT TITLE FROM BOOKS,PUBLISHER
WHERE BOOKS.PUBLISHER_ID= PUBLISHER.PUBLISHER_ID and PUBLISHER.LAND='England'
mittels Join. Die Idee bei Subqueries geht
so, bilde eine Menge der Publisher_ID aus der Publisher Tabelle, und dann
nehme nur die Bücher mit einer derartigen Publisher_ID. Dies geht
folgendermassen:
SELECT TITLE FROM BOOKS WHERE PUBLISHER_ID
= ANY (
die Formulierung ANY bedeutet, dass die
Operation (=) wahr wird wenn mindestens ein Wert aus der Tabelle der subquery
passt. Äquivalent ginge dies auch mit der schon bekannten IN verknüpfung:
SELECT TITLE FROM BOOKS WHERE PUBLISHER_ID
IN (
Das Gegenteil ist die Abfrage nach den
Büchern die nicht aus England kommen:
SELECT TITLE FROM BOOKS WHERE PUBLISHER_ID
<> ALL (
oder aber auch NOT IN. Auch das Beispiel
für den Auto Join lässt sich umformulieren, es ging um Bücher
die billiger als das Buch Programming in SQL war. Die Anfrage mit Join
war:
SELECT x.TITLE FROM BOOKS x, BOOKS y
WHERE y.TITLE='Programming in SQL' AND x.TITLE LIKE '%SQL%' AND x.PRICE
< y.PRICE
Ohne Join geht es so:
SELECT TITLE FROM BOOKS WHERE TITLE
LIKE '%SQL%' AND PRICE <= ALL (
Erlaubt ist ferner folgende Syntay wenn
die subquery genau eine Zeile liefert, was in diesem Beispiel der Fall
sein sollte (es existiert ein sog. Titelschutz, d.h. erigentlich ist auch
ein Buchtitel ein Schlüssel)
SELECT TITLE FROM BOOKS WHERE TITLE
LIKE '%SQL%' AND PRICE <= (
d.h. in fehlt das ALL/IN/ANY/NOT IN muss
die subquery genau eine Zeile liefern. All diese Anfragen kann man als
eine zweistufige Abfrage auffassen, zuerst wird die subquery ausgewertet,
danach die äussere Anfrage. Im folgenden Beispielen ist das anders:
SELECT * FROM BOOKS A WHERE PRICE >
ALL (
aus Perfomrancegründen gibt es häufig
Einschränkungen in der Anzahl der Parameter die in die subquery übergeben
werden (im Beispiel 2). Daher ist diese subquery auf manchen System wo
nur eine erlaubt ist, nicht lauffähig. Ferner sind derartige verknüpfte
Schachtelungen meist nicht iterierbar. Diese Einschränkungen gelten
bei der folgenden Methode nicht.
SELECT TITLE FROM BOOKS WHERE EXISTS
(
Der Unterschied zu obiger Variante sind
die unterschiedlichen Auswertungsreihenfolgen. Diese Variante entspricht
dem Join und ist langsamer als vorhergehende zweistufige. Um ein Beispiel
zu bekommen die mittels EXISTS über die Möglichkeiten des Joins
hinausgehen erweitern wir die Buchhandlungsdatenbank um eine Tabelle LIEFERANT,
die aus zwei Spalten besteht, ISBN und GROSSIST_ID und eine Zeile bedeutet,
dass das entsprechende Buch von dem jeweiligen Grossisten geliefert wird.
Eine zweite Tabelle GROSSIST soll zur GROSSIST_ID die notwendigen Daten
enthalten. Das erste Beispiel, das noch per JOIN geht ist
SELECT ISBN FROM BOOKS WHERE EXISTS
(
auch die Verneinung geht, dann wären
es Bücher die von keinem Grossisten geliefert werden und daher direkt
vom Verlag zu bestellen sind:
SELECT ISBN FROM BOOKS WHERE NOT EXISTS
(
das ginge schon nicht mehr mit einem Join
aber noch durch eine NOT IN Abfrage, die folgende kann aber nur mit EXISTS
formuliert werden. Gesucht sind die Bücher die von allen Grossisten
geliefert werden:
SELECT ISBN FROM BOOKS WHERE NOT EXISTS
(
auch hier kann die innere Anfrage (dies
sind Grossisten die ein Buch nicht liefern) als NOT IN formuliert werden.
Insgesamt geht das nicht denn die innerste Suchbedingung greift auf alle
drei SELECT Anweisungen zu, und das ist nur bei EXISTS erlaubt.
Bei den vorgestellten Methoden mittels
subqueries Abfragen zu formulieren ging es oft um mengentheoretische Operation
auf den Ergebnismengen. Es gibt auch die Möglichkeit diese Operationen
direkt zu formulieren. Die entsprechendne Namen sind
SELECT Anweisung Verknüpfung
SELECT Anweisung
dabei muss darauf geachtet werden, dass
die Formate (Spalten Anzahl, Typ) kompatibel sind. Ein einfaches Beispiel
wäre eine Liste der Geschäftspartner, dies sind entweder Verlage
oder Grossisten
SELECT PUBLISHER_ID,NAME, ADRESS FROM
PUBLISHER
das Ergebnis ist eine Tabelle mit dem gleichen
Spaltennamen wie die erste Menge und den Einträgen aus beiden Tabellen.
Voraussetzung ist die Kompatibilität, d.h. CHAR unterschiedlicher
Länge ist kein Problem, aber dürfen z.B. nicht INTEGER und CHAR
aufeinander treffen. Dies ist eine mengentheoretische Operation, d.h. im
Ergebnis kommen keine doppelten Zeilen vor. Will man andere Spaltennnamen
so muss man in der ersten SELECT Anweisung aliases definieren. Es ist klar,
dass sämtliche mengentheoretische Verknüpfungen auch anders (Join,
geschachtelt) umformuliert werden können.
COMMIT WORK;
und
ROLLBACK WORK;
zur Verfügung, mit denen eine Transaktion
entweder bestätigt oder rückgängig gemacht wird. Standardmäßig
werden bei allen Datenbanken (erzeugt mit CREATE DATABASE) die SQL-Anweisungen
innerhalb einer Transaktion ausgeführt. D.h bei keinen
vorgenommenen COMMITS kann alles seit dem öffnen der Datenbank rückgängig
gemacht werden. Lediglich bei Datenbanken, die explizit mit dem Zusatz
NO LOG angelegt wurden, steht keine Transaktionsverwaltung zur Verfügung.
Bei diesen Datenbanken können die Anweisungen COMMIT WORK und ROLLBACK
WORK nicht verwendet werden. Wird eine Transaktion über ROLLBACK WORK
zurückgesetzt, gilt die Einschränkung, daß nur DML Anweisungen
(INSERT,UPDATE, DELETE) auf reguläre Tabellen (keine Systemtabellen)
rückgängig gemacht werden können. In einer Transaktion können
Savepoints definiert werden, die es ermöglichen, daß durch eine
ROLLBACK Anweisung nicht die gesamte Transaktion, sondern nur der Teil
seit dem letzten Savepoint zurückgesetzt wird. Ein Savepoint wird
durch einen eindeutigen Namen identifiziert und kann jederzeit über
die Anweisung
SAVEPOINT savepoint-name;
definiert werden. Mit der Anweisung
ROLLBACK WORK TO SAVEPOINT savepoint-name;
wird die Transaktion bis zum Status bei
der Definition des Savepoints zurückgesetzt. Es können beliebig
viele Savepoints definiert werden. Beim Ende einer Transaktion (COMMIT/ROLLBACK)
werden alle bestehenden Savepoints gelöscht. Ein einzelner Savepoint
kann jederzeit über die Anweisung
RELEASE SAVEPOINT;
freigegeben werden.
-
geringere
Netzwerkbelastung im Client-Server Betrieb
Eine Stored Procedure ist eine benutzerdefinierte
Routine die von jedem Datenbankbenutzer über die SQL-Anweisungen
CREATE
Beispiel:
Das folgende Beispiel zeigt die CREATE
FUNCTION Anweisung und den PL-Code zur Generierung der Funktion wochentag,
wie sie in SQL ausgeführt werden kann:
CREATE FUNCTION wochentag(tagnr INTEGER)
In diesem Beispiel ist die Funktion wochentag
eine ausschließlich mit PL-Anweisungen erstellte Funktion, die zu
einer Nummer von 1-7 den entsprechenden Tag liefert. Über die
RETURNS Klausel wird der Datentyp und die Anzahl der Rückgabewerte
festgelegt. In diesem Fall wird genau ein Wert vom Typ CHAR mit der maximalen
Länge 20 zurückgegeben. Innerhalb der CASE Anweisung sind
die RETURN Anweisungen zur Rückgabe des Wertes angegeben. In
einer Funktion sind die RETURNS Klausel und mindestens eine RETURN Anweisung
zwingender Bestandteil.
Erstellen einer Routine in Embedded SQL
Soll eine Routine über ein ESQLC-Programm
erstellt werden, muß sich der PL-Code der Routine in einer Stringkonstanten,
einer Hostvariablen oder einer Datei befinden. Die Routine kann dann über
die CREATE PROCEDURE FROM Anweisung angelegt
EXEC SQL CREATE FUNCTION FROM
Wichtig ist hierbei, daß der Text
der Routine eine vollständige CREATE FUNCTION oder CREATE PROCEDURE
Anweisung enthalten muß.
ISBN
AUTOR
TITLE
PUBLISHER_ID
PRICE
1.2.2 WHERE
Schlüsselwort
< Kleiner
> Größer
<= Kleiner gleich
>= Größer gleich
<> Verschieden
1.2.3 Zusammenfassen von Zeilen (Aggregatzeilen)
MAX()
MIN()
SUM()
das ist die Summe
1.2.4 ORDER BY
SELECT * FROM BOOKS ORDER BY PRICE;
Die normale Sortierreihenfolge ist ansteigend,
es sei denn man spezifiziert absteigend mit dem Schlüsselwort DESC.
Bei Textfeldern wird die lexikographische Reihenfolge genommen. Will man
zuerst nach Autor und innerhalb des Autors nach Preis, dann geht das so:
1.2.5 select mit join
Europe
SL62QL
ISBN
AUTOR
TITLE
PRICE
PUBLISHER_ID
NAME
ADRESS
LAND
FAX
FON
der bisher besprochene SELECT fällt
natürlich in die erste Kategorie.
1.3 CREATE TABLE, DROP TABLE, ALTER TABLE
NUMBERS
...
...
...
...
1.4 INSERT, UPDATE, DELETE
1.5. Views
Views (Sichten) sind neben Joins das entscheidende
Merkmal einer relationalen Datenbank. Ein Sicht ist eine virtuelle Tabelle,
die, basierend auf einer SELECT Anweisung, einen Ausschnitt des Datenbestandes
zur Verfügung stellt. Dabei werden in einer Sicht nicht wie bei einer
temporären Tabelle Daten gespeichert, sondern die Sicht wird jederzeit
dynamisch an die zugrundeliegenden Tabellen angepaßt. Damit läßt
sich mit Sichten ein sehr flexibler Zugriff auf die Daten realisieren,
da sie wie ein Filter auf den Datenbestand wirken. Eine Sicht wird
mit der Anweisung
Einschränkungen. Um mit den Befehlen
INSERT, DELETE und UPDATE auf einen View zugreifen zu können, muß
ein View
veränderbar (updatable) sein. Ein
View ist updatable, wenn alle der folgenden Bedingungen zutreffen:
1.6 Zugriffsrechte
Views sind eine gute Möglichkeit
nur Teilmengen der Tabelle der Öffentlichkeit zugänglich
zu machen. Will man als online Buchhändler nicht aller Welt verraten
wieviel Bücher man verkauft, so ist es geschickt einen View zu definieren,
der die Spalte NUMBERS nicht mit weitergibt:
Man kann auch mehrere Rechte gleichzeitig
gewähren:
1.7 SCHLÜSSEL, INDEX
Schlüssel in einer Tabelle sind
Attributmengen, die Zeilen eindeutig beschreiben. Sie sind Kernstück
bei der Entwicklung von Normalformen, d.h. beim Entwurf von Datenbank.
Man hat die Möglichkeit bei der Definition die Schlüsseleigenschaft
anzugeben:
Was passiert wenn
ein Datensatz gelöscht wird / verändert wird, auf den mittels
Fremdschlüssel zugegriffen wird?
Der Normalfall ist, dass es nicht erlaubt
ist einen entsprechenden Datensatz zu Löschen/Verändern. Man
kann dies durch die erweiterte FOREIGN KEY Syntax ändern:
(
col1 INTEGER,
col2 INTEGER,
col3 INTEGER
);
1.8 DATABASE Befehl
Eine Datenbank bezeichnet eine Menge
von Tabellen, die logisch zusammengehören. Jede Tabelle, außer
den Systemtabellen (data dictionary), gehört zu genau einer Datenbank.
Neben den Tabellen können in einer Datenbank noch weitere Datenbankobjekte
angelegt werden: Views, Synonyme, Indizes, Domains, Prozeduren, Funktionen,
Trigger und Constraints. Jeder Benutzer muß nach der Anmeldung an
ein Datenbanksystem über die
SQL-Anweisungen beziehen. Bei der Auswahl
einer neuen Datenbank muß vorher
die aktuelle Datenbank geschlossen werden
dazu die
1.9. Trigger
Über Trigger lassen sich SQL Anweisungen
festlegen, die automatisch gestartet werden, wenn ein bestimmtes Ereignis
für eine Tabelle eintritt. Der Einsatz von Triggern ist z.B. für
die folgenden Aufgaben sinnvoll:
Die Definition eines Triggers erfolgt
über die
Ebenso wie das Ereignis festgelegt
wird, das einen Trigger auslöst, muß auch der Zeitpunkt festgelegt
werden, zu dem die Aktionen gestartet werden sollen. Dabei gibt es sechs
verschiedene Möglichkeiten:
Beispiele für die Definition eines
Triggers:
ausgeführt wird, ein INSERT in die
Tabelle log_file ausgeführt.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1.10 geschachtelte SELECT Anweisungen
1.10.1 einfache Schachtelungen (IN, ALL, ANY)
Geschachtelte SELECT Anweisungen sind
Anweisungen die eine weitere SELECT Anweisungen als Unterabfrage
(subquery) enthalten. Unterabfrage bedeutet die SELECT Anweisung ist Bestandteil
des Suchteils, der mit WHERE eingeleitet wird. Die Unterabfrage wird in
Klammern eingeschlossen. D.h allgemein sieht es so aus
SELECT PUBLSIHER_ID FROM PUBLISHER WHERE LAND='England');
SELECT PUBLSIHER_ID FROM PUBLISHER WHERE LAND='England');
SELECT PUBLSIHER_ID FROM PUBLISHER WHERE LAND='England');
SELECT PRICE FROM BOOKS WHERE TITLE='Programming in SQL');
SELECT PRICE FROM BOOKS WHERE TITLE='Programming in SQL');
1.10.2 verknüpfte Schachtelungen (IN)
Wenn nun Spalten aus der äusseren
Abfrage in der subquery auftauchen, dann ist der Aufwand ähnlich wie
beim Join, d.h. für jedes äussere Tupel wird eine subquery fällig,
z.B. um die teuersten Bücher von jedem Verleger zu finden
SELECT BOOKS B WHERE B.PUBLISHGER_ID = A.PUBLISHER_ID AND A.ISBN != B.ISBN);
1.10.3 verknüpfte Schachtelungen (EXISTS)
Hier sind auch innere und äussere
Anfrage verknüpft. Man interesiert sich aber nun in der subquery nicht
für eine spezielle Spalte, sonder nur ob sie ein Ergebnis geliefert
hat. Als einfaches Beispiel kann man so auch wieder die Abfrage nach
Büchern aus England lösen
SELECT * FROM PUBLISHER WHERE LAND='England' AND
PUBLISHER.PUBLISHER_ID = BOOKS.PUBLISHER_ID );
SELECT * FROM LIEFERANT WHERE BOOKS.ISBN = LIEFERANT.ISBN);
SELECT * FROM LIEFERANT WHERE BOOKS.ISBN = LIEFERANT.ISBN);
SELECT * FROM GROSSIST WHERE NOT EXISTS(
SELECT * FROM LIEFERANT WHERE LIEFERANT.GROSSIST_ID = LIEFERANT.GROSSIST_ID
AND
LIEFERANT.ISBN = BOOKS.ISBN));
1.10.4 Mengentheoretische Verknüpfungen
(UNION,INTERSECT,MINUS)
UNION
Vereinigung
INTERSECT
Schnitt
MINUS oder EXCEPT
Komplement
Der prinzpielle Aufbau ist:
UNION
SELECT GROSSIST_ID,NAME,ADRESS FROM
GROSSIST;
1.11 Transaktionen
Transaktionen bieten die Möglichkeit,
mehrere SQL-Anweisungen logisch zusammenzufassen, so daß entweder
alle Anweisungen ausgeführt werden oder keine. Tritt bei einer Anweisung
ein Fehler auf, oder wurden z.B. versehentlich falsche Werte gespeichert,
können alle Anweisungen einer Transaktion rückgängig gemacht
werden, solange diese Transaktion noch nicht bestätigt wurde. Dafür
stehen die beiden speziellen Anweisungen
-
-
1.12 Prozeduren
Damit handelt es sich um eine Erweiterung
von SQL (query language) zu einer Programmiersprache. Man spricht
von der procedure language (PL). Während die klassische Datenbankprogrammierung
eine klare Trennung zwischen der Datenbank und der Anwendung vorsieht,
ist es mit Hilfe der PL möglich, ganze Anwendungsteile in Form einer
Stored Procedure in der Datenbank zu hinterlegen. Damit sind eine Reihe
von Vorteilen verbunden, wie z.B.
verbesserte
Performance
anwendungsweit
einheitliche Implementierung von Algorithmen
höhere
Portabilität
FUNCTION oder CREATE PROCEDURE
angelegt werden kann. Der Benutzer muss hierzu Eigentümer der Datenbank
sein oder das RESOURCE Recht in der aktuellen Datenbank haben. Routinen
können aus SQL, PL oder einer Kombination aus SQL und PL-Anweisungen
bestehen. Beim Anlegen der stored procedure wird diese kompiliert in der
Datenbank abgelewgt. Der Unterschied zwischen PROCEDURE unD FUNCTION ist
wie z.B. in PASCAL, dass eine PROCEDURE keinen Rückgabewert hat.
1.12.1 Aufbau einer Routine
Eine Routine wird durch einen Header
eingeleitet. Der Header besteht aus dem Namen der Routine, einer optionalen
Parameterliste und der RETURNS Klausel, wenn es sich um eine Funktion handelt.
Die Routine selbst besteht aus beliebig vielen Blöcken von PL- und/oder
SQL-Anweisungen. Ein Block wird eingeleitet durch das Schlüsselwort
BEGIN und endet mit dem Schlüsselwort END. Es kann nur einen äußeren
BEGIN/END Block in einer Routine geben. Innerhalb dieses Blocks können
jedoch weitere BEGIN/END
(geschachtelt) integriert werden. Besteht
eine Routine aus genau einer (ausführbaren) PL- oder SQL-Anweisung,
muß kein BEGIN/END Block definiert werden. Innerhalb eines BEGIN/END
Blocks können deklarative und ausführbare Anweisungen vorkommen.
Alle Deklarationen müssen am Anfang eines Blocks direkt hinter dem
Schlüsselwort BEGIN stehen. Es stehen alle wesentlichen Programmiersprachenkonstrukte
zur Verfügung: FOR/WHILE/CASE/Variablen/BREAK-CONTINUE/Funktionsaufrufe/..
RETURNS CHAR(20);
BEGIN
CASE tagnr
WHEN 1 THEN RETURN ('Sonntag');
WHEN 2 THEN RETURN ('Montag');
WHEN 3 THEN RETURN ('Dientag');
WHEN 4 THEN RETURN ('Mittwoch');
WHEN 5 THEN RETURN ('Donnerstag');
WHEN 6 THEN RETURN ('Freitag');
WHEN 7 THEN RETURN ('Samstag');
ELSE RETURN ('Unbekannt');
END CASE
END
END FUNCTION;
werden. Das folgende Beispiel zeigt
das Anlegen der Funktion wochentag über eine Stringkonstante in einem
ESQLC-Programm:
'CREATE FUNCTION wochentag(tagnr INTEGER)
RETURNS CHAR(20);
BEGIN
CASE tagnr
WHEN 1 THEN RETURN ('Sonntag');
WHEN 2 THEN RETURN ('Montag');
WHEN 3 THEN RETURN ('Dientag');
WHEN 4 THEN RETURN ('Mittwoch');
WHEN 5 THEN RETURN ('Donnerstag');
WHEN 6 THEN RETURN ('Freitag');
WHEN 7 THEN RETURN ('Samstag');
ELSE RETURN ('Unbekannt');
END CASE
END
END FUNCTION';