16 Die eingebettete SQL-Sprache
16.1.1 Kennzeichnen der eingebetteten
SQL-Anweisungen
16.2 Eingebettete SQL-Anweisungen ohne
Cursor
16.4 Übersetzung eines ESQL/C- bzw.
ESQL/COBOL-Programms
16.5 Eingebettete Anweisungen und
Programmierstil
16.5.1 Optimierung der Datenbankzugriffe
16.5.2 Explizite Abfrage bei der Änderung von
Reihen
16.5.3 Explizite Angabe aller Reihen in einer
SELECT- bzw.
In diesem Kapitel werden die
eingebetteten SQL-Anweisungen
bei
INGRES beschrieben, wie sie in den Programmiersprachen
C
und COBOL benutzt
werden können. Zuerst
werden
die
eingebetteten
SQL-Anweisungen ohne Cursor-Benutzung
dargestellt. Im zweiten
Teil des Kapitels
werden die
Anwendung des Cursors erklärt und alle SQL-Anweisungen, die
im Zusammenhang mit dem
Cursor benutzt werden, erläutert.
Der
letzte Teil des
Kapitels ist dem
Programmierstil
gewidmet; anhand von Beispielen wird erklärt, wie
man ein
Anwendungsprogramm mit
Hilfe einfacher Regeln
optimieren
kann.
In
den bisherigen Kapiteln, die sich mit den SQL-Anweisungen
von
INGRES befaßt haben,
haben wir erklärt,
wie diese
Anweisungen interaktiv, d.h. direkt
am Bildschirm benutzt
werden können. Die
andere Möglichkeit stellt die Benutzung
der
Anweisungen innerhalb eines
Anwendungsprogramms
dar. Ob
SQL-Anweisungen interaktiv oder
in einem
Anwendungsprogramm benutzt werden, hängt von der Art ihrer
Verwendung ab. Interaktiv werden
die Anweisungen meist
benutzt, wenn
Datendefinitionsanweisungen
bzw. einfache
Datenmanipulationsanweisungen
angegeben werden sollen.
Die
eingebetteten SQL-Anweisungen werden vor allem
dann
verwendet, wenn komplexe Abfragen
und Änderungen einer
Datenbank durchgeführt werden sollen. Dabei ist die Linie,
die diese zwei Verwendungsarten
trennt, nicht genau. Es kommt
sowohl vor, daß eine
Datendefinitionsanweisung eingebettet
benutzt wird, als auch,
daß komplexere Abfragen
und
Änderungen der Datenbank interaktiv
durchgeführt werden.
Die interaktiven und eingebetteten SQL-Anweisungen sind im
Prinzip sehr ähnlich; der
größte Unterschied ist, daß die
eingebettete SQL-Sprache zusätzliche Anweisungen beinhaltet,
die
bei der interaktiven
Anwendung nicht vorkommen.
Jede
SQL-Anweisung, die
interaktiv verwendet wird,
kann also
auch
eingebettet in einem
Anwendungsprogramm, eventuell
mit kleinen Änderungen, benutzt
werden. (Diese Änderungen
betreffen nur die Datenmanipulationsanweisungen und
von
diesen besonders die
SELECT-Anweisung.)
INGRES unterstützt z.Zt. in
der UNIX- und VMS-Umgebung die
Schnittstellen zu folgenden Programmiersprachen der dritten
Generation:
- Ada ,
- C,
- COBOL,
-
FORTRAN,
- Basic,
- Pascal und
- PL/I.
Alle Beispiele in diesem und im
nächsten Kapitel sind in
zwei
Programmiersprachen - C und COBOL -
geschrieben. Wir
haben uns für diese beiden Sprachen
aus folgendem Grund
entschieden: COBOL ist
noch immer die
meistverwendete
Programmiersprache für die kommerziellen Anwendungen und C
die
wichtigste Sprache für die
Betriebssysteme UNIX und
DOS.
Trotz dieser Einschränkung
auf COBOL und C gelten die
Beschreibungen in diesem
und im nächsten Kapitel generell
für alle INGRES-Schnittstellen zu den
Programmiersprachen der
dritten Generation.
Wir
gehen davon aus, daß jeder Leser
entweder die eine oder
die andere Programmiersprache kennt. Es ist nicht notwendig,
die
Beispiele in beiden
Sprachen nachzuvollziehen; sie
sind
so gestaltet, daß jedem COBOL-Beispiel ein ähnliches
C-Beispiel unmittelbar folgt.
Die eingebetteten
SQL-Anweisungen können auf
zwei
verschiedene Weisen
abgearbeitet werden. Meist
wird ein
Vorübersetzer zur Verfügung gestellt, der jede SQL-Anweisung
in
die Host-Sprache übersetzt.
Damit wird, nach
der
Vorübersetzer-Phase, ein
Programm mit einheitlichem Code
erzeugt, das anschließend übersetzt
werden kann.
Die
andere Möglichkeit, die
eingebetteten Anweisungen
abzuarbeiten, ist, eine
Modulbibliothek zu verwenden und jede
SQL-Anweisung an den entsprechenden Modul zu übergeben. Die
Verwendung der Modulbibliothek kommt in der Praxis nicht so
oft vor wie die Verwendung des
Vorübersetzers.
Alle
INGRES-Schnittstellen zu den
Sprachen der dritten
Generation enthalten einen Vorübersetzer, der die
eingebetteten SQL-Anweisungen in die
Host-Sprache übersetzt.
Die INGRES-Komponente SQL/FORMS, die eine Erweiterung der
eingebetteten SQL ist und die Erstellung der
maskenbasierten
Anwendungen ermöglicht, wird in
diesem Buch nicht
beschrieben. Die Beschreibung dieser
Komponente finden Sie in
den entsprechenden INGRES-Manualen.
Damit ein Vorübersetzer die
eingebetteten SQL-Anweisungen von
den
Anweisungen der Host-Sprache
unterscheiden kann, ist es
erforderlich, alle SQL-Anweisungen
besonders zu kennzeichnen.
Dabei muß sowohl der
Anfang, als auch
das Ende einer
SQL-Anweisung gekennzeichnet werden.
Die
eingebetteten SQL-Anweisungen haben am Anfang als Präfix
die Schlüsselwörter
EXEC SQL .
Dies gilt für alle
INGRES-Schnittstellen. Das Ende
einer eingebetteten
SQL-Anweisung wird für
verschiedene
Host-Sprachen unterschiedlich gekennzeichnet. Bei COBOL wird
das Schlüsselwort "END-EXEC." und bei C das Zeichen ";" als
Endekennzeichen benutzt.
In
einem Anwendungsprogramm werden
am häufigsten
Datenmanipulationsanweisungen (SELECT,
INSERT, UPDATE und
DELETE) verwendet. Jede dieser
Anweisungen ermöglicht
den Datenaustausch mit
Hilfe von Variablen
zwischen dem
Anwendungsprogramm einerseits und der
Datenbank andererseits.
Die
Variablen befinden sich
innerhalb der eingebetteten
SQL-Anweisung und
sind nichts anderes
als Variablen
der
Host-Sprache, die auch
als solche definiert
werden
müssen. Damit sie innerhalb
der SQL-Anweisung von
den
Datenbankobjekten unterschieden
werden können, werden sie mit
dem Präfix ":" gekennzeichnet.
In
der eingebetteten SQL-Anweisung existieren zwei
unterschiedliche Arten von Variablen
-
Host-Variablen und
- Indikator-Variablen.
Host-Variablen dienen
als Ziel-Variablen einer
Abfrage bzw. können anstelle
einer Konstante in
den
Datenmanipulationsanweisungen
verwendet werden. Sie
können
auch
als Argumente in verschiedenen
anderen SQL-Anweisungen
verwendet werden.
Host-Variablen können
nur die Datentypen
haben, die in
den
Host-Sprachen erlaubt sind.
Auf der anderen
Seite
werden ihnen die Datenwerte zugewiesen bzw. werden
sie mit
Datenwerten verglichen,
die SQL-Datentypen haben. Damit die
Zuweisung bzw. ein Vergleich durchgeführt werden kann,
muß
jede Variable zu ihrem
entsprechenden Datenwert
kompatibel
sein.
Indikator-Variablen sind spezielle
Variablen, die nur
im
Zusammenhang mit Host-Variablen benutzt werden können. Jede
Host-Variable kann also eine
zugehörige Indikator-Variable
haben, die zusätzliche Information
über den gespeicherten
Wert in der Host-Variablen liefert. Die Host-Variable und die
dazu gehörende Indikator-Variable werden immer nacheinander
in der folgenden Form geschrieben:
:hostvar:indvar .
Indikator-Variablen ermöglichen:
- die Prüfung, ob einer
Host-Variablen ein NULL-Wert
zugewiesen wurde;
- die Prüfung, ob bei der
Zuweisung eines Datenwertes an
eine Host-Variable der
zugewiesene Wert gekürzt wird
und damit Information verloren
geht;
- das Einfügen von NULL-Werten.
Wenn
in einer SELECT-Anweisung ein
Datenwert, der einen
NULL-Wert enthält, einer Host-Variablen zugewiesen wird,
beinhaltet die Host-Variable nach
der Zuweisung einen
undefinierten Wert. Die Prüfung einer solchen Zuweisung kann
mit
Hilfe einer Indikator-Variablen durchgeführt werden,
die dann den Wert -1 enthält,
während die entsprechende
Host-Variable unverändert bleibt.
Wenn
in einer SELECT-Anweisung ein Datenwert gekürzt
einer Host-Variablen zugewiesen
wird (z.B. wenn die Länge
der
Host-Variablen kleiner als die
definierte Länge des
Datenwertes ist), kann dies mit Hilfe
der Indikator-Variablen
festgestellt werden.
In diesem Fall
enthält die
Indikator-Variable die tatsächliche Länge des zugewiesenen
Datenwertes.
Anstatt das Schlüsselwort NULL in
einer INSERT- bzw.
UPDATEAnweisung
zu verwenden, kann das Einfügen eines NULL-Wertes
mit
Hilfe der Indikator-Variablen durchgeführt werden.
In diesem Fall muß der
Indikator-Variablen der Wert
-1
zugewiesen werden (siehe Beispiel
16.7).
Alle
Indikator-Variablen werden in einer Host-Sprache intern
als 2 Byte lange Ganzzahlen gespeichert. Bei COBOL kann jede
Indikator-Variable mit
S9(5) COMP
und bei
C mit
short (bzw. short int)
definiert
werden.
Jede Host- bzw. Indikator-Variable
muß explizit definiert
werden, wobei die Variablen mit Datenbankobjekten gleichnamig
sein können. In jedem Programm wird
ein spezieller Abschnitt,
der
sogenannte DECLARE-Abschnitt aufgebaut, in dem nur Host-
und
Indikator-Variablen definiert
werden dürfen. In jedem
Programm darf nur ein
DECLARE-Abschnitt existieren.
Der DECLARE-Abschnitt beginnt mit der
SQL-Anweisung
BEGIN DECLARE SECTION
und endet mit einer weiteren
SQL-Anweisung
END DECLARE SECTION .
Diese beiden eingebetteten SQL-Anweisungen müssen
als solche
innerhalb des Programms
gekennzeichnet sein. In COBOL
wird
also jede von ihnen zwischen den
Schlüsselwörtern
EXEC SQL und
END-EXEC.
geschrieben.
Die
SQL-Anweisungen BEGIN DECLARE
SECTION und END
DECLARE SECTION sind keine
ausführbaren SQL-Anweisungen,
im Gegensatz zu
allen bis jetzt
beschriebenen. Sie
gehören zu Vereinbarungs-Anweisungen,
von welchen weitere
im
Verlauf dieses Kapitels
vorgestellt werden. Im
Unterschied zu ausführbaren
SQL-Anweisungen generieren die
Vereinbarungs-Anweisungen keinen
Code.
Die folgenden
Beispiele zeigen die
Form des
DECLARE-Abschnitts in COBOL bzw. in
C.
Beispiel 16.1
(COBOL)
EXEC SQL BEGIN DECLARE SECTION END-EXEC.
77 VORNAME
PIC X(15).
77 NACHNAME
PIC X(15).
77 IND-VORNAME PIC S9(5)
COMP.
77 IND-NACHNAME PIC S9(5)
COMP.
EXEC SQL END DECLARE SECTION END-EXEC.
Beispiel 16.2
(C)
EXEC SQL BEGIN DECLARE SECTION;
char vorname[16];
char nachname[16];
short ind_vorname;
short ind_nachname;
EXEC SQL END DECLARE SECTION;
Eine weitere, in
jedem Programm befindliche
eingebettete
SQL-Anweisung ist die
CONNECT-Anweisung. Mit dieser Anweisung
wird
das Programm mit einer Datenbank
verbunden. Die Syntax
dieser Anweisung ist
CONNECT db_name [IDENTIFIED BY ben] [OPTIONS=sch_1,...]
Die
Angaben der CONNECT-Anweisung sind den
Angaben des in
Kapitel 15 beschriebenen sql-Kommandos
ähnlich. Die Angabe
IDENTIFIED BY entspricht dem Schalter "-u" und sch_1,...
den
anderen vom sql-Kommando
unterstützten Schaltern. db_name ist
der Name der Datenbank, mit der
das Programm verbunden ist.
db_name kann auch mit
Hilfe einer Host-Variablen
definiert
werden.
Die CONNECT-Anweisung muß jeder
anderen SQL-Anweisung, die in
Bezug zur Datenbank db_name
steht, vorangehen. Ein Programm
kann zu einem Zeitpunkt nur
mit einer einzigen Datenbank
verbunden werden.
Die zweite Anweisung
DISCONNECT
beendet die Verbindung zu
einer Datenbank. Diese
SQL-Anweisung ist
unbedingt notwendig, falls
in einem
Programm die Verbindung zu
einer zweiten Datenbank
hergestellt werden soll. In
diesem Fall muß
zuerst
die
Verbindung zur ersten
Datenbank mit Hilfe
der
DISCONNECT-Anweisung beendet
werden, bevor mit
der
CONNECT-Anweisung die
Verbindung zu der
neuen Datenbank
aufgebaut wird.
Mit der Anweisung CALL ermöglicht
INGRES den Aufruf eines
Betriebssystemkommandos bzw.
eines Subsystems (wie
QBF,
Report-Writer usw.)
aus einem Programm
heraus. Diese
Anweisung hat zwei verschiedene Formen
CALL SYSTEM (COMMAND = kommando)
bzw.
CALL subsystem (DATABASE=db_name
[,param_1=wert_1,...])
Mit der
ersten Form der
CALL-Anweisung kann ein
Betriebssystemkommando
und mit der
zweiten ein
INGRES-Subsystem aufgerufen werden.
INGRES unterstützt drei verschiedene
Möglichkeiten, bei einer
eingebetteten SQL-Anweisung zu prüfen, ob sie erfolgreich
ausgeführt wurde. Diese Möglichkeiten
sind:
- die Prüfung der
SQLCA-Struktur,
- die Verwendung der WHENEVER-Anweisung oder
- die Verwendung der
INQUIRE_INGRES-Anweisung.
Nach
der Abarbeitung jeder
ausführbaren SQL-Anweisung wird
die Information, ob diese
Anweisung erfolgreich ausgeführt
wurde, an eine spezielle
Struktur geliefert. Diese Struktur
heißt SQLCA (SQL Communication Area) und muß
in jedem
Host-Programm explizit eingefügt werden, damit die in ihr
gespeicherte Information benutzt werden kann. Das Einfügen
der SQLCA-Struktur erfolgt mit folgender SQL-Anweisung:
INCLUDE SQLCA
Die
INCLUDE-Anweisung ist eine
Vereinbarungs-Anweisung.
Während der
Vorübersetzungs-Phase wird diese
Anweisung
durch die Definition mehrerer
Host-Variablen ersetzt. Diese
Host-Variablen enthalten
Informationen über die
gerade
ausgeführte SQL-Anweisung.
Jedes Programm führt standardmäßig die eingebettete
SQL-Anweisung aus, ohne sich um
eventuell aufgetretene Fehler
zu kümmern. Mit Hilfe der
Host-Variablen, die in der
SQLCAStruktur
definiert sind, ist
es möglich, den Zustand des
Programms nach jeder ausführbaren
SQL-Anweisung zu überprüfen
und eventuell notwendige Maßnahmen zu
treffen.
Bei allen Programmiersprachen enthält
die SQLCA-Struktur u.a.
folgende Variablen:
- SQLCODE,
- SQLERRM,
- SQLERRD und
- SQLWARN.
SQLCODE ist ein 4 Byte langes,
binäres Datenfeld, das den
Rückgabewert der zuletzt ausgeführten SQL-Anweisung
enthält.
Ist
der Rückgabewert 0, wurde die
SQL-Anweisung erfolgreich
ausgeführt.
Bei
einem Fehler im Programm, der in
einer SQL-Anweisung
aufgetreten ist, wird der
Rückgabewert negativ. Jedem
existierenden negativen Rückgabewert
entspricht eine
Fehlermeldung, deren
Text in den entsprechenden Manualen des
Systems nachgelesen werden kann.
Der
positive Rückgabewert zeigt
eine Warnung an, wie z.B.
im Falle einer SELECT-Anweisung, die keine einzige Reihe als
Ergebnis liefert.
SQLERRM ist eine variabel
lange Zeichenkette, die den Text
der Fehlermeldung enthält, der dem
negativen Rückgabewert der
Variablen SQLCODE entspricht.
SQLERRD ist ein Vektor mit 6 Elementen, die als 4 Byte lange
binäre Datenfelder definiert sind. Diese Datenfelder sollen
den
internen Zustand des
Systems beschreiben. Z.Zt.
wird
nur
SQLERRD(3) unterstützt, das die Anzahl der verarbeiteten
Reihen bei einer
Datenmanipulationsanweisung anzeigt.
SQLWARN ist eine Struktur
mit 8 Elementen, die als
1
Byte
lange alphanumerische Datenfelder definiert sind.
Jedes dieser Datenfelder zeigt Warnungen für verschiedene
Bedingungen an, die nach der
Ausführung einer SQL-Anweisung
auftreten können. Der Wert
jedes Datenfeldes kann entweder
das Zeichen "W" oder das
Leerzeichen sein, abhängig davon, ob
eine entsprechende Bedingung aufgetreten
ist oder nicht.
In
der Praxis sollte nach jeder ausführbaren SQL-Anweisung
der
Wert der SQLCODE-Variablen
überprüft werden. Falls der
Rückgabewert ungleich
0 ist, sollten weitere Maßnahmen
ergriffen werden. Beispiel 16.5 zeigt, wie die Prüfung
der
SQLCODE-Variablen aussehen könnte.
Als
Alternative zur expliziten Prüfung der SQL-Anweisungen
mit
Hilfe der SQLCA-Struktur bietet sich die Benutzung der
WHENEVER-Anweisung an. Sie ist eine Vereinbarungs-Anweisung,
die
jede eingebettete SQL-Anweisung
nach ihrer Ausführung
überprüft. Die allgemeine Form der
WHENEVER-Anweisung ist
WHENEVER bedingung massnahme
wobei bedingung die Werte
-
SQLERROR,
- SQLWARNING,
- NOT FOUND
sowie
- SQLMESSAGE
und massnahme die Werte
- GO
TO marke,
- STOP,
- CONTINUE
und
- CALL prozedur
haben
kann.
SQLERROR kennzeichnet die Bedingung,
die erfüllt ist,
wenn ein Fehler nach der
Ausführung einer SQL-Anweisung
aufgetreten ist, wenn also
der Rückgabewert der
SQLCODE-Variablen negativ ist.
SQLWARNING kennzeichnet die Bedingung, die erfüllt ist, wenn
mindestens eine Warnung vom
System gemeldet wird. In
dem
Fall
wird das erste Datenfeld des Vektors SQLWARN überprüft;
falls der Wert gleich "W"
ist, wird die Bedingung als erfüllt
betrachtet.
NOT
FOUND kennzeichnet die
Bedingung, die erfüllt ist, wenn
keine oder keine weitere Reihe
nach der Ausführung einer
Datenmanipulationsanweisung gefunden wird. Dieser Fall tritt
auf, wenn der Rückgabewert der
SQLCODE-Variablen 100 ist.
Die
Bedingung SQLMESSAGE tritt auf,
falls der Wert
der
SQLCODE-Variablen 700 beträgt. Diese
Warnung kennzeichnet die
Ausführung der MESSAGE-Anweisung in
einer Datenbankprozedur.
GO TO marke setzt den
Ablauf des Programms ab der
Stelle
fort, die mit "marke"
gekennzeichnet ist, falls die Bedingung
in
der WHENEVER-Bedingung erfüllt
ist. Diese Maßnahme
entspricht dem Einfügen der Anweisung
IF bedingung THEN GO TO marke
nach
jeder ausführbaren SQL-Anweisung in einem Programm.
Mit STOP wird
ein fehlerhaftes Programm
nach der
Ausgabe einer Fehlermeldung beendet.
Eine zu diesem
Zeitpunkt eröffnete Datenbank
wird geschlossen (d.h.
die
DISCONNECT-Anweisung wird vom System
implizit durchgeführt.)
CONTINUE kennzeichnet die
Fortsetzung des Programms, ohne
Maßnahmen zu ergreifen. Damit entspricht diese Klausel
dem
Fall, in dem keine
zusätzliche IF-Anweisung nach
jeder
ausführbaren SQL-Anweisung eingeführt
wird.
CALL prozedur verursacht den Aufruf einer Prozedur, die
Teil
der
Hostsprache ist (z.B. die Ausführung eines Abschnitts
entsprechend der PERFORM-Anweisung in
COBOL).
Die Wirkung einer WHENEVER
SQLERROR-Anweisung beschränkt sich
von ihrer Position im Modul,
wo sie angegeben ist, bis zur
nächsten WHENEVER SQLERROR-Anweisung bzw. bis zum Modulende,
falls keine weitere WHENEVER
SQLERROR-Anweisung existiert.
Die Voreinstellung für WHENEVER SQLERROR-Anweisung ist
die
CONTINUE-Angabe. Die WHENEVER SQLERROR-Anweisung
muß erst
nach
der Anweisung INCLUDE SQLCA im
Programm erscheinen, um
überhaupt benutzt werden zu können.
Für WHENEVER SQLWARNING bzw. WHENEVER NOT FOUND gilt alles,
was
bereits über WHENEVER SQLERROR gesagt wurde.
Die INQUIRE_INGRES-Anweisung
ist eine spezifische
INGRES-Anweisung, die
dem Benutzer die
Möglichkeit
bietet, nach jeder ausgeführten SQL-Anweisung die
Diagnoseinformationen den
unterschiedlichen Host-Variablen
eines Programms zuzuweisen. Die
Syntax dieser Anweisung ist
INQUIRE_INGRES (host_var1=angabe_1
[,host_var2=angabe_2,..])
angabe_1, angabe_2,... sind
die unterschiedlichen Angaben der
INQUIRE_INGRES-Anweisung. Die wichtigsten von ihnen liefern
dieselbe Information wie die
unterschiedlichen Variablen
der
SQLCA-Struktur (z.B. entspricht
die Angabe ROWCOUNT
SQLERRD(3), die Angabe ERRORTEXT
SQLERRM usw.)
Die
Entscheidung, ob die
Fehlerbehandlung explizit mit
der
Prüfung der SQLCA-Struktur oder implizit mit
Hilfe
der WHENEVER- bzw. der INQUIRE_INGRES-Anweisung
durchgeführt
werden soll, ist dem
Programmierer überlassen. Jede
dieser Methoden hat Vor-
und Nachteile: Die
Logik der
WHENEVER-Anweisung ist
komplizierter als die
explizite
Prüfung der SQLCA-Struktur und
die Verwendung der
GO
TO-Anweisung kann zu
unübersichtlichen
Programmen führen.
Auf der anderen Seite erfordert
die explizite Prüfung der
SQLCA-Struktur einen erhöhten
Programmieraufwand. Wichtig ist
nicht, welche Methode gewählt
wird, sondern daß auf jeden
Fall eine Fehlerbehandlung in den
Programmen stattfindet.
In
den meisten Beispielen
dieses und des nächsten
Kapitels, die nur Teilprogramme oder einzelne
eingebettete
SQL-Anweisungen zeigen, werden wir auf die Fehlerbehandlung
verzichten, damit sie so
klein wie möglich gehalten
werden
können. In den Beispielen, die ganze Programme umfassen wird
die explizite Prüfung des
Wertes der SQLCODE-Variablen in
den COBOL-Programmen durchgeführt
während die C-Programme die
WHENEVER-Anweisung beinhalten.
Die eingebetteten SQL-Anweisungen, die ohne Cursor verwendet
werden können, sind:
- alle Datendefinitionsanweisungen;
- alle Datensteuerungsanweisungen;
- die SELECT-Anweisung, die nur
eine Reihe als
Ergebnis
liefert;
- die UPDATE-Anweisung
ohne CURRENT-Klausel
- die DELETE-Anweisung
ohne CURRENT-Klausel;
- die INSERT-Anweisung.
Anhand von Beispielen werden
die obigen SQL-Anweisungen
dargestellt. Wie bereits
in den vorhergehenden, wird auch
in
diesen Beispielen die
Beispieldatenbank verwendet.
Beispiel 16.3
Versorgen Sie die Host-Variablen MNAME und MVORNAME mit den
Werten des Namens und
Vornamens jedes Mitarbeiters, dessen
Personalnummer durch die
Host-Variable PERSNUM gegeben ist.
(COBOL)
EXEC SQL
SELECT m_name, m_vorname
INTO :MNAME, :MVORNAME
FROM mitarbeiter
WHERE m_nr = :PERSNUM
END-EXEC.
(C)
EXEC SQL
SELECT m_name, m_vorname
INTO
:MNAME, :MVORNAME
FROM
mitarbeiter
WHERE m_nr = :PERSNUM;
Im Unterschied
zur interaktiven SELECT-Anweisung beinhaltet
die
eingebettete SELECT-Anweisung die INTO-Klausel mit einer
Reihe von Variablen. Die INTO-Klausel
hat folgende Form
INTO
:hostvar1[:indvar1] [, :hostvar2[:indvar2]] ...
Liefert die
Bedingung in der
WHERE-Klausel in Beispiel
16.3
nur eine Reihe als Ergebnis,
werden die entsprechenden
Datenwerte der Spalten m_name und m_vorname der
Host-Variablen MNAME und MVORNAME zugewiesen.
Wenn die
Bedingung für keine der
Reihen der Tabelle
mitarbeiter
erfüllt ist, wird der
Wert der SQLCODE-Variable auf 100
gesetzt. Falls die Bedingung mehr als
eine Reihe als Ergebnis
liefert, wird SQLCODE auf
einen negativen Wert gesetzt.
Jede
der Host-Variablen MNAME,
MVORNAME und PERSNUM
muß
einen kompatiblen Datentyp
zu ihrem entsprechenden
Datenwert m_name, m_vorname bzw. m_nr haben. Die
notwendigen
Datenkonvertierungen führt das
System durch. Die
Spalten
m_name und m_vorname sind als
CHAR(20) definiert, während
m_nr als INTEGER definiert
ist. Dementsprechend könnte der
DECLARE-Abschnitt für die
Host-Variablen wie folgt aussehen:
(COBOL)
EXEC SQL BEGIN
DECLARE SECTION END-EXEC.
77 MNAME PIC X(20).
77 MVORNAME PIC X(20).
77 PERSNUM PIC S9(9) COMP.
EXEC SQL END DECLARE SECTION END-EXEC.
(C)
EXEC SQL
BEGIN DECLARE SECTION;
char MNAME[21];
char MVORNAME[21];
int PERSNUM;
EXEC SQL END DECLARE
SECTION;
Beispiel
16.4
Versorgen Sie die Host-Variablen ABTNR und STADT mit der
Abteilungsnummer und dem Standort für jene Abteilung, deren
Name
durch die Host-Variable ABTNAME
gegeben ist. Den
Host-Variablen ABTNR und STADT
sollen die Indikator-Variablen
INDABTNR und INDSTADT
zugewiesen werden.
(COBOL)
EXEC SQL
SELECT abt_nr, stadt
INTO :ABTNR:INDABTNR,
:STADT:INDSTADT
FROM abteilung
WHERE abt_name =
:ABTNAME
END-EXEC.
(C)
EXEC SQL
SELECT abt_nr, stadt
INTO :ABTNR:INDABTNR,
:STADT:INDSTADT
FROM
abteilung
WHERE abt_name = :ABTNAME;
Die Indikator-Variablen sind
schon im vorherigen Abschnitt
beschrieben worden. Mit Hilfe
der Indikator-Variablen
INDSTADT kann z.B. überprüft werden, ob der
Host-Variablen
STADT ein NULL-Wert zugewiesen wurde bzw. ob der
zugewiesene
Wert
gekürzt wurde. (Mit der Indikator-Variablen INDABTNR
kann
nur geprüft werden,
ob der zugewiesene Wert der
Host-Variablen ABTNR gekürzt wurde, weil
die Spalte abt_nr
keine NULL-Werte zuläßt.)
Wie
aus Beispiel 16.4
ersichtlich, kann eine Host-Variable
denselben Namen wie ihre
entsprechende Spalte haben.
Der
Vorübersetzer erkennt grundsätzlich
die Host- bzw.
IndikatorVariablen
an dem Präfix ":".
Die
Indikator-Variablen dürfen
nicht in der
WHERE- bzw.
HAVING-Klausel verwendet werden.
Der DECLARE-Abschnitt für Beispiel
16.4 könnte so aussehen:
(COBOL)
EXEC
SQL BEGIN DECLARE SECTION END-EXEC.
77 ABTNR PIC X(4).
77 STADT
PIC X(15).
77 ABTNAM PIC X(20).
77 INDABTNR PIC S9(5) COMP.
77 INDSTADT PIC S9(5) COMP.
EXEC SQL END DECLARE SECTION END-EXEC.
(C)
EXEC SQL
BEGIN DECLARE SECTION;
char
ABTNR[5];
char STADT[16];
char ABTNAM[21];
short INDABTNR, INDSTADT;
EXEC SQL END DECLARE SECTION;
Im
nächsten Beispiel wird die Benutzung der Host-Variablen in
der HAVING-Klausel gezeigt.
Beispiel 16.5
Die
Host-Variable PRNR soll
mit der Nummer des
Projektes
versorgt werden, an dem genau die dem
Wert der Host-Variablen
ANZAHL entsprechende Anzahl von
Mitarbeitern beteiligt ist.
Nach der Ausführung der
SELECT-Anweisung soll die Prüfung der
SQLCODE-Variablen durchgeführt
werden.
(COBOL)
EXEC SQL
SELECT pr_nr
INTO :PRNR
FROM arbeiten
GROUP BY pr_nr
HAVING COUNT(*) = :ANZAHL
END-EXEC.
IF SQLCODE OF SQLCA <
0 THEN
DISPLAY "Fehler in SELECT"
DISPLAY SQLCODE OF SQLCA
STOP RUN
ELSE DISPLAY
"Select-Anweisung ausgefuehrt".
(C)
EXEC SQL
SELECT
pr_nr
INTO
:PRNR
FROM arbeiten
GROUP BY pr_nr
HAVING COUNT(*) = :ANZAHL
if (SQLCA.SQLCODE < 0)
{
printf ("Fehler in SELECT\n");
printf ("%d\n",
SQLCA.SQLCODE);
exit (SQLCA.SQLCODE);
}
Die
Fehlerbehandlung in Beispiel
16.5 überprüft zuerst
den
Wert der SQLCODE-Variablen nach der Ausführung
der
SELECT-Anweisung. Wenn
dieser Wert kleiner
0 ist, wird
zuerst der Rückgabewert und
danach der entsprechende
Fehlermeldungstext ausgegeben.
Anschließend wird das Programm
beendet. Wenn der Wert
der SQLCODE-Variablen größer
gleich
0 ist, wird lediglich die
Bestätigung für die ausgeführte
SELECT-Anweisung ausgegeben.
Das
nächste Beispiel zeigt die Verwendung der Host-Variablen
in der VALUES-Klausel der
INSERT-Anweisung.
Beispiel 16.6
Fügen Sie eine Reihe
mit den Datenwerten
einer neuen
Abteilung ein, deren Nummer, Name und Standort jeweils
durch
die Host-Variablen ABTNR, ABTNAME
und STADT gegeben sind.
(COBOL)
MOVE
"a4" TO ABTNR.
MOVE "Test" TO
ABTNAME.
MOVE "Freiburg"
TO STADT.
EXEC SQL
INSERT
INTO abteilung(abt_nr, abt_name, stadt)
VALUES(:ABTNR, :ABTNAME, :STADT)
END-EXEC.
(C)
strcpy(ABTNR, "a4");
strcpy(ABTNAME,
"Test");
strcpy(STADT,
"Freiburg");
EXEC SQL
INSERT INTO abteilung(abt_nr,abt_name,stadt)
VALUES
(:ABTNR, :ABTNAME, :STADT);
Wie im folgenden Beispiel ersichtlich, können
Indikator-Variablen verwendet werden, um NULL-Werte
einzufügen.
Beispiel 16.7
Fügen Sie eine Reihe mit den
Datenwerten eines neuen Projekts
ein, dessen Nummer, Name und Mittel durch die Host-Variablen
PRNR, PRNAME und MITTEL gegeben
sind. Der Wert
der
zugewiesenen Geldmittel ist noch
nicht bekannt.
(COBOL)
MOVE
"p1" TO PRNR.
MOVE "Mars" TO
PRNAME.
MOVE -1 TO INDMITTEL.
EXEC SQL
INSERT INTO
PROJEKT(pr_nr, pr_name, mittel)
VALUES(:PRNR,
:PRNAME, :MITTEL:INDMITTEL)
END-EXEC.
(C)
strcpy(PRNR,"p1");
strcpy(PRNAME, "Mars");
INDMITTEL
= -1;
EXEC
SQL
INSERT INTO PROJEKT(pr_nr, pr_name, mittel)
VALUES(:PRNR, :PRNAME, :MITTEL:INDMITTEL);
Durch die Zuweisung des Wertes
-1 an die Indikator-Variable
INDMITTEL vor der INSERT-Anweisung, wird der
Datenwert der
Spalte mittel auf NULL gesetzt.
Das
nächste Beispiel zeigt die
Benutzung der Host-Variablen
in der SET-Klausel der
UPDATE-Anweisung.
Beispiel 16.8
Ändern Sie die Aufgabe des Mitarbeiters in Projekt p2 mit
Hilfe der Host-Variablen AUFGABE. Die
Personalnummer des
Mitarbeiters ist durch die
Host-Variable MNR gegeben.
(COBOL)
MOVE "Gruppenleiter" TO
AUFGABE.
MOVE 18316 TO MNR.
EXEC
SQL
UPDATE arbeiten
SET aufgabe = :AUFGABE:INDAUFGABE
WHERE m_nr = :MNR
AND pr_nr = 'p2'
END-EXEC.
(C)
strcpy (AUFGABE, "Gruppenleiter");
MNR = 18316;
EXEC SQL
UPDATE arbeiten
SET aufgabe = :AUFGABE:INDAUFGABE
WHERE m_nr = :MNR
AND pr_nr = 'p2';
In einer
DELETE-Anweisung können die
Host-Variablen in der
WHERE-Klausel verwendet werden.
Beispiel 16.9
Löschen Sie die Datenwerte des
Projektleiters in dem Projekt,
dessen Nummer durch die Variablen PRNR
gegeben ist.
(COBOL)
MOVE
"p1" TO PRNR.
EXEC
SQL
DELETE FROM arbeiten
WHERE AUFGABE = 'Projektleiter'
AND pr_nr = :PRNR
END-EXEC.
(C)
strcpy
(PRNR, "p1");
EXEC
SQL
DELETE FROM arbeiten
WHERE AUFGABE = 'Projektleiter'
AND pr_nr = :PRNR;
Obwohl die
Datenmanipulationsanweisungen
von allen
SQL-Anweisungen am
häufigsten in eine
Host-Sprache
eingebettet werden, kann dies
ebenso mit den
Datendefinitions- wie auch mit den
Datensteuerungsanweisungen
durchgeführt werden.
Das folgende Beispiel
zeigt die
Einbettung einer CREATE
INDEX-Anweisung.
Beispiel 16.10
Erstellen Sie einen
zusammengesetzten Index für die Spalten
m_nr und einst_dat der
Tabelle arbeiten.
(COBOL)
EXEC SQL
CREATE INDEX i_mnr_dat ON
arbeiten(m_nr,einst_dat)
END-EXEC.
(C)
EXEC SQL
CREATE
INDEX i_mnr_dat ON arbeiten(m_nr,einst_dat);
Das
folgende Programm zeigt
die Verwendung der
SELECT-Anweisung in einem
COBOL-Programm.
Beispiel 16.11
Finden Sie Namen und
Vornamen des Mitarbeiters, dessen
Personalnummer am Bildschirm
eingegeben wird.
IDENTIFICATION
DIVISION.
PROGRAM-ID. BSP1611.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL BEGIN DECLARE SECTION
END-EXEC.
77
MNAME PIC X(20) VALUE SPACES.
77
MVORNAME PIC X(20) VALUE SPACES.
77
MNR PIC S9(9) COMP.
EXEC SQL END DECLARE SECTION
END-EXEC.
EXEC SQL INCLUDE SQLCA END-EXEC.
PROCEDURE DIVISION.
A1.
PERFORM DBOPEN.
PERFORM A100-SELECT.
PERFORM DBCLOSE.
STOP RUN.
DBOPEN.
EXEC SQL
CONNECT BEISPIEL
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY
"FEHLER BEIM DB-OEFFNEN"
STOP RUN.
A100-SELECT.
DISPLAY "Geben Sie die Mitarbeiternummer
an".
ACCEPT MNR.
EXEC SQL
SELECT m_name, m_vorname
INTO :MNAME, :MVORNAME
FROM mitarbeiter
WHERE m_nr = :MNR
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
SELECT"
ELSE
DISPLAY "Select
ausgefuehrt".
DISPLAY
"Der Mitarbeiter mit der Personalnummer: ", MNR.
DISPLAY "heisst: ", MNAME, MVORNAME.
DBCLOSE.
EXEC SQL
DISCONNECT
END-EXEC.
Im
A100-SELECT-Abschnitt wird der
Vergleich in der
WHERE-Klausel der SELECT-Anweisung durchgeführt und die
ausgewählten Datenwerte der Spalten m_name und m_vorname
werden den Host-Variablen MNAME und MVORNAME zugewiesen. Das
Ergebnis der SELECT-Anweisung ist immer eine einzige Reihe,
weil jeder Mitarbeiter eine eindeutige
Personalnummer hat.
Der
Abschnitt DBOPEN erstellt
die Verbindung zu
der
entsprechenden Datenbank. Das wird mit der
SQL-Anweisung
CONNECT durchgeführt. Der letzte
Abschnit DBCLOSE beendet die
Verbindung zwischen der Datenbank und
dem Programm.
Die
Fehlerbehandlung in Beispiel
16.11, wie in
allen
nachfolgenden Beispielen, ist mit der expliziten Prüfung der
SQLCODE-Variablen durchgeführt
worden.
Das folgende C-Programm ist mit dem
vorherigen COBOL-Beispiel
identisch.
Beispiel 16.12
/* Beispiel 16.12 */
EXEC SQL
INCLUDE sqlca;
#include <stdio.h>
EXEC SQL BEGIN DECLARE SECTION;
char
m_name[21 ];
char m_vorname[21];
int m_nr;
EXEC SQL END DECLARE SECTION;
main()
{
EXEC SQL
WHENEVER SQLERROR
GO TO :fehler;
EXEC SQL
CONNECT beispiel;
printf("Geben
Sie die Nummer des Mitarbeiters an:\n");
scanf ("%d", &m_nr);
EXEC SQL
SELECT m_name, m_vorname
INTO :m_name, :m_vorname
FROM mitarbeiter
WHERE m_nr = :m_nr;
printf("Mitarbeiter mit der Personalnummer
%d\n",m_nr);
printf("heisst: %s %s\n", m_name ,m_vorname);
exit(0);
fehler: printf ("Fehler: %d\n",sqlca.sqlcode);
EXEC SQL
DISCONNECT ;
}
Im
folgenden Beispiel wird
die Änderung der
Datenwerte
mittels einer UPDATE-Anweisung
gezeigt.
Beispiel 16.13
Ändern Sie die Aufgabe jenes
Mitarbeiters, dessen Personal-
und Projektnummer am Bildschirm
eingegeben werden.
IDENTIFICATION
DIVISION.
PROGRAM-ID. BSP1613.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL BEGIN DECLARE SECTION
END-EXEC.
77
PRNR PIC X(4) VALUE SPACES.
77
AUFGABE PIC X(15) VALUE SPACES.
77
MNR PIC S9(9) COMP.
77
IND-AUFGABE PIC S9(5) COMP.
EXEC SQL END DECLARE SECTION
END-EXEC.
EXEC SQL INCLUDE SQLCA END-EXEC.
PROCEDURE DIVISION.
A1.
PERFORM DBOPEN.
PERFORM A100-SELECT.
PERFORM A200-UPDATE.
PERFORM DBCLOSE.
STOP RUN.
DBOPEN.
EXEC SQL
CONNECT BEISPIEL
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY
"FEHLER BEIM DB-OEFFNEN"
STOP RUN.
A100-SELECT.
DISPLAY "Geben Sie die Mitarbeiternummer
an".
ACCEPT MNR.
DISPLAY "Geben Sie die Projektnummer an".
ACCEPT PRNR.
EXEC SQL
SELECT aufgabe
INTO
:AUFGABE
FROM arbeiten
WHERE m_nr = :MNR
AND pr_nr = :PRNR
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
SELECT"
ELSE
DISPLAY "Select
ausgefuehrt".
DISPLAY
"Der Mitarbeiter mit der Personalnummer: ", MNR.
DISPLAY "arbeitet im Projekt ", PRNR,
"als ", AUFGABE.
DISPLAY "Geben Sie die neue Aufgabe des
Mitarbeiters an".
ACCEPT AUFGABE.
A200-UPDATE.
EXEC SQL
UPDATE arbeiten
SET aufgabe = :AUFGABE:IND-AUFGABE
WHERE m_nr = :MNR
AND pr_nr = :PRNR
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
UPDATE"
ELSE
DISPLAY
"UPDATE ausgefuehrt".
DBCLOSE.
EXEC SQL
DISCONNECT
END-EXEC.
Das
Programm beinhaltet unter
anderem zwei Abschnitte:
A100-SELECT und
A200-UPDATE. Mit dem
ersten Abschnitt
wird die Aufgabe des Mitarbeiters, dessen Personal- und
Projektnummer eingegeben
sind, ausgewählt und am
Bildschirm
angezeigt. Damit wird im
Programm eine zusätzliche
Überprüfung der Datenwerte eingebaut. Im Abschnitt
A200-UPDATE wird schließlich die Änderung der Aufgabe des
Mitarbeiters durchgeführt.
Das
folgende C-Programm entspricht dem vorherigen
COBOL-Beispiel.
Beispiel 16.14
/* Beispiel 16.14 */
#include <stdio.h>
EXEC SQL
INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
char pr_nr[5];
char
aufgabe[16];
int m_nr;
short ind_aufgabe;
EXEC SQL END DECLARE SECTION;
main()
{
EXEC SQL
WHENEVER SQLERROR
GO TO :fehler;
EXEC SQL
CONNECT beispiel;
printf("Geben
Sie die Nummer des Mitarbeiters an:\n");
scanf ("%d", &m_nr);
printf("Geben
Sie die Projektnummer an\n");
scanf("%s", pr_nr);
EXEC
SQL
SELECT aufgabe
INTO :aufgabe
FROM arbeiten
WHERE m_nr = :m_nr
AND pr_nr = :pr_nr;
printf("Der
Mitarbeiter mit der Personalnummer: %d\n",m_nr);
printf("ist %s im Projekt %s\n\n",aufgabe
,pr_nr);
printf("Geben Sie die neue Aufgabe des Mitarbeiters
an:\n");
scanf("%s", aufgabe);
EXEC SQL
UPDATE arbeiten
SET aufgabe =
:aufgabe:ind_aufgabe
WHERE m_nr = :m_nr
AND pr_nr =
:pr_nr;
exit(0);
fehler: printf ("Fehler: %d\n", sqlca.sqlcode);
EXEC SQL
DISCONNECT;
}
INGRES unterstützt die Anweisung
DECLARE tab_name TABLE ,
die
Spalten einer Tabelle, gemeinsam mit ihren Datentypen
auflistet. Diese Anweisung ist
keine ausführbare
SQL-Anweisung, sondern dient nur als Kommentar innerhalb des
Variablendeklarationsteils. Mit der DECLARE
TABLE-Anweisung
ist
es lediglich möglich, die
Dokumentation eines Programms
zu
verbessern. Sie wird
auch vom Dienstprogramm DCLGEN
verwendet.
Das Dienstprogramm DCLGEN
("Declaration Generator") generiert
automatisch eine Struktur in
der eingebetteten Sprache,
die
analog dem Schema einer Tabelle ist. D.h. jede Spalte
einer Tabelle wird in
der generierten Struktur
durch
eine
entsprechende Variable
dargestellt. Die so generierte
Struktur erleichtert das Einlesen
der Datenwerte einer
Tabellenreihe in
das Programm, bzw.
das Schreiben der
Datenwerte aus dem Programm in eine
Tabellenreihe.
Mit dem Betriebssystemkommando
dclgen sprache db_name tab_name dat_name struk_name
kann
dieses Dienstprogramm aufgerufen werden. sprache
definiert die eingebettete Programmiersprache, während
db_name, tab_name und struk_nmame jeweils
Datenbank-,
Tabellen- und Strukturnamen
darstellen.
dat_name ist
der Name der
Ausgabedatei, die die
von
DCLGEN generierte
Strukturdeklaration
enthält. Diese
Datei enthält auch die DECLARE
TABLE-Anweisung, die als
Gedächtnisstütze für das
Tabellenschema dient. Mit
Hilfe
der Vereinbarungsanweisung INCLUDE ist es möglich, die Datei
dat_name dem Deklarationsteil
eines Programms hinzufügen.
Im vorherigen Abschnitt haben wir gezeigt, wie man Abfragen
durchführen kann, wenn die eingebettete SELECT-Anweisung nur
eine Reihe als Ergebnis liefert. Wenn die Anzahl der Reihen,
die eine SELECT-Anweisung liefert,
im voraus nicht bekannt
bzw. größer als eins ist, muß zusätzlicher Aufwand betrieben
werden, damit alle Reihen der
Abfrage ausgewählt werden
können. Der Grund dafür liegt in
den Unterschieden zwischen
SQL einerseits und den Host-Sprachen
andererseits.
SQL
ist eine mengenorientierte Sprache. Mit den
Datenmanipulationsanweisungen wie SELECT,
DELETE usw. wird
also vom Benutzer nicht
festgelegt, wie der
Weg zum
gewünschten Ergebnis erreicht werden soll, sondern lediglich
das,
was gemacht werden soll. Dadurch kann der Benutzer in
der
Regel nicht wissen, wieviele Reihen eine Abfrage liefern
wird.
Die
Host-Sprachen können nicht
gleichzeitig mehrere
Datensätze bearbeiten, sondern holen
sich einen Datensatz
nach
dem anderen. Damit
dieser Unterschied zwischen
Host-Sprachen und
SQL überbrückt werden
kann, wird ein
Datenpuffer benutzt, in welchem
dann alle Reihen, die als
Ergebnis einer Abfrage ausgewählt
wurden, gespeichert werden.
Dieser Datenpuffer wird mit einer Art Zeiger bearbeitet, der
bei SQL Cursor heißt.
Der
Cursor hat gewisse
Ähnlichkeiten mit einer Datei. Jede
Datei muß zuerst definiert werden.
Danach wird sie eröffnet
und
anschließend wird sequentiell
ein Datensatz nach dem
anderen bearbeitet. Am Ende wird die
Datei geschlossen.
Für einen Cursor gilt
dasselbe. Für jeden
der genannten
Schritte existiert in der
eingebetteten SQL-Sprache je eine
zusätzliche Anweisung, die im
interaktiven Modus nicht
vorhanden ist. Diese Anweisungen
sind:
-
DECLARE CURSOR,
- OPEN,
- FETCH
und
- CLOSE.
Mit der
DECLARE CURSOR-Anweisung wird ein Cursor definiert.
Diese Anweisung gehört zu den
SQL-Vereinbarungs-Anweisungen
und sie hat folgende allgemeine Form:
DECLARE cursor_name CURSOR FOR
select_anw [FOR UPDATE
[DEFERRED|DIRECT] OF spalte_1,...]
cursor_name kennzeichnet den Namen
des definierten Cursors,
der
eindeutig innerhalb eines
Host-Programms sein muß.
Der
Name kann eine
Konstante oder eine
alphanumerische
Host-Variable sein und ist
nur innerhalb des Host-Programms
bekannt, in dem er definiert wurde.
select_anw bezeichnet
eine SELECT-Anweisung (oder
eine
Vereinigung mehrerer
SELECT-Anweisungen mit Hilfe
des
Operators UNION), die fest
mit dem Cursor
cursor_name
verbunden ist.
Jeder Cursor, der mit
der "FOR UPDATE"-Klausel definiert
ist, kann später in einer
UPDATE- bzw. DELETE-Anweisung
mit
der CURRENT OF-Klausel
benutzt werden (siehe
die
Erklärung für diese
beiden Anweisungen später
in diesem
Kapitel). spalte_1,... kennzeichnet alle Spalten, die mit
der UPDATE-Anweisung modifiziert
werden können. Der DEFERRED-
bzw. DIRECT-Modus bei der
FOR UPDATE-Klausel definiert den
Zeitpunkt der Änderungen der Reihen, die mit
dem Cursor
definiert sind. Beim DEFERRED-Modus
werden alle Änderungen an
den
Reihen erst beim Schließen des Cursors durchgeführt. Der
DIRECT-Modus führt die Änderungen der
Reihen zu dem Zeitpunkt
der Ausführung einer UPDATE- bzw. einer
DELETE-Anweisung aus.
Damit werden im DIRECT-Modus die
Änderungen an den Reihen für
das
Programm, das der Cursor
eröffnet hat, gleich sichtbar.
Falls keiner der beiden Modi explizit angegeben ist, wird
DEFERRED standardmäßig angenommen.
Die
DECLARE CURSOR-Anweisung muß
vor jeder anderen
SQL-Anweisung im
Programm erscheinen, die
den in ihr
definierten Cursor verwenden will.
Die Gültigkeit der
Cursor-Definition erstreckt sich auf
das ganze Host-Programm,
in dem sie definiert wurde.
Im
Unterschied zu der DECLARE CURSOR-Anweisung sind die drei
anderen SQL-Anweisungen, die Cursor
betreffen, ausführbare
SQL-Anweisungen. Mit der Anweisung
OPEN cursor_name
[FOR READONLY]
wird die SELECT-Anweisung, die sich
innerhalb der DECLARE
CURSOR-Anweisung befindet, ausgeführt. Das
Ergebnis einer
solchen SELECT-Anweisung wird oft
die Treffermenge ("active
set") genannt. Die optionale Klausel FOR READONLY teilt dem
System mit, daß die
Treffermenge nur gelesen,
und nicht
geändert wird.
Nach
der Ausführung der OPEN-Anweisung steht der Cursor
vor
der ersten Reihe der Treffermenge. Die Änderung der
Host-Variablen in der WHERE-Klausel
der SELECT-Anweisung nach
der
Ausführung der OPEN-Anweisung
ändert nicht die einmal
festgelegte Treffermenge. Diese
Änderung hat erst dann eine
Wirkung, wenn die OPEN-Anweisung noch
einmal ausgeführt wird.
Ein
erneutes Öffnen des Cursors mit Hilfe der OPEN-Anweisung
bedeutet also das implizite Schließen des Cursors und das
Erstellen eines neuen Kriteriums
für die in der SELECT-
Anweisung verwendeten Host-Variablen.
Mit der FETCH-Anweisung wird der
Cursor auf der nächsten
Reihe der Treffermenge
positioniert. Diese Anweisung
hat
folgende Form
FETCH cursor_name INTO :host_var1[,:host_var2] ...
Der
Cursor muß zuvor definiert und eröffnet werden. Nach
der
ersten FETCH-Anweisung wird die
Treffermenge festgelegt
und der Cursor
auf die erste Reihe positioniert. Die
Reihen
der Treffermenge können nur sequentiell abgearbeitet werden.
Der
Cursor kann also in diesem Fall nur vorwärts von einer
Reihe zur nächsten bewegt
werden. Die FETCH-Anweisung,
die
ausgeführt wird, nachdem
der Cursor schon
auf die
letzte Reihe der Treffermenge positioniert war,
weist der
SQLCODE-Variablen den Wert 100 zu.
Mit der Anweisung
CLOSE cursor_name
wird ein eröffneter Cursor
geschlossen. Mit dieser
Anweisung wird der Cursor
nur inaktiv; eine anschließende
OPEN-Anweisung eröffnet
ihn wieder. Durch
eine Änderung
der
Host-Variablen, die sich
in der WHERE-Klausel der
SELECT-Anweisung befinden,
kann das Kriterium
für die
Treffermenge neu
definiert werden. Eine
FETCH-Anweisung
mit einem geschlossenen Cursor wird
vom System mit einer
Fehlermeldung abgewiesen. Die Anweisungen COMMIT
und
ROLLBACK schließen alle eröffneten
Cursor.
Das folgende Beispiel zeigt die Verwendung des
Cursors in
einem COBOL-Programm.
Beispiel 16.15
Finden Sie
Personalnummer, Namen, Vornamen und
Abteilungsnummer der
Mitarbeiter, deren Personalnummer
kleiner als der am
Bildschirm eingegebene Wert
ist. Die
ausgewählten Reihen
sollen nach Personalnummern sortiert
werden.
IDENTIFICATION DIVISION.
PROGRAM-ID. BSP1615.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL BEGIN DECLARE SECTION
END-EXEC.
77
MNAME PIC X(20) VALUE SPACES.
77
MVORNAME PIC X(20) VALUE SPACES.
77
ABTNR PIC X(4) VALUE SPACES.
77
MNR PIC S9(9) COMP.
77
MINZAHL PIC S9(9) COMP.
EXEC SQL END DECLARE SECTION
END-EXEC.
EXEC SQL INCLUDE SQLCA END-EXEC.
PROCEDURE DIVISION.
A1.
PERFORM DBOPEN.
PERFORM A100-DECLARE.
PERFORM A200-OPEN.
PERFORM A300-FETCH UNTIL SQLCODE OF SQLCA = 100.
PERFORM A400-CLOSE.
PERFORM DBCLOSE.
STOP RUN.
DBOPEN.
EXEC SQL
CONNECT BEISPIEL
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY
"FEHLER BEIM DB-OEFFNEN"
STOP RUN.
A100-DECLARE.
DISPLAY
"Geben Sie die obere Grenze an".
ACCEPT MINZAHL.
EXEC SQL
DECLARE crs_mit CURSOR FOR
SELECT
m_nr, m_name, m_vorname, abt_nr
FROM mitarbeiter
WHERE m_nr < :MINZAHL
ORDER BY m_nr
END-EXEC.
A200-OPEN.
EXEC SQL
OPEN crs_mit
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
OPEN".
A300-FETCH.
EXEC SQL
FETCH crs_mit
INTO :MNR, :MNAME, :MVORNAME,
:ABTNR
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
FETCH".
IF SQLCODE OF SQLCA NOT = 100
DISPLAY MNR,"
",MNAME," ",MVORNAME," ",ABTNR.
A400-CLOSE.
EXEC SQL
CLOSE crs_mit
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
CLOSE".
DBCLOSE.
EXEC SQL
DISCONNECT
END-EXEC.
In Beispiel 16.15 existieren
vier Programmabschnitte, die
genau den vier beschriebenen SQL-Anweisungen DECLARE CURSOR,
OPEN, FETCH und CLOSE entsprechen. Im Abschnitt A100-DECLARE
wird der Cursor crs_mit
definiert. Der
A200-OPEN-Abschnitt
führt die OPEN-Anweisung aus. Die
Festlegung der Treffermenge
und
die Ausführung der
FETCH-Anweisung für jede
Reihe
wird
im Programmabschnitt A300-FETCH
durchgeführt. Mit dem
A400-CLOSE-Abschnitt wird der Cursor crs_mit
geschlossen.
Das folgende C-Programm ist mit dem
vorherigen COBOL-Programm
identisch.
Beispiel 16.16
/* Beispiel 16.16 */
#include <stdio.h>
EXEC SQL
INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
char
m_name[21];
char m_vorname[21];
int m_nr, min_zahl;
EXEC SQL END DECLARE SECTION;
main()
{
EXEC SQL
WHENEVER SQLERROR
GO TO :fehler;
EXEC SQL
WHENEVER NOT FOUND
GOTO :schlies;
EXEC SQL
CONNECT beispiel;
printf("Geben Sie die obere Grenze an\n");
scanf ("%d", &min_zahl);
EXEC SQL
DECLARE crs_mit CURSOR FOR
SELECT
m_nr, m_name, m_vorname
FROM
mitarbeiter
WHERE m_nr < :min_zahl
ORDER by m_nr;
EXEC SQL
OPEN crs_mit;
for (;;)
{
EXEC SQL
FETCH crs_mit
INTO :m_nr, :m_name,
:m_vorname;
printf("%d
%s%s\n",m_nr,m_name,m_vorname);
}
schlies:
EXEC SQL
CLOSE crs_mit;
EXEC SQL
DISCONNECT;
exit(0);
fehler: printf ("Fehler: %d\n", sqlca.sqlcode);
}
In
der DECLARE CURSOR-Anweisung - wie aus ihrer Definition
ersichtlich - existiert eine
zusätzliche Klausel
FOR UPDATE OF spalte_1 [,spalte_2,...]
Mit dieser
Klausel werden die
ausgewählten Reihen mit
Hilfe eines Cursors geändert bzw.
gelöscht.
Die
Voraussetzung für das
Ändern der Datenwerte
bzw.
das Löschen der Reihen ist das Vorhandensein der CURRENT
OF-Klausel innerhalb der UPDATE-
bzw. DELETE-Anweisung. Die
UPDATE-Anweisung hat dann folgende
Form
UPDATE tab_name
SET (sp_1=ausdr_1,...)
WHERE CURRENT OF
cursor_name
cursor_name ist der Name
des Cursors, der in der
DECLARE
CURSOR-Anweisung mit der FOR
UPDATE-Klausel definiert ist.
(Die DELETE-Anweisung hat eine
analoge Form.)
Der
Cursor cursor_name muß
eröffnet werden, bevor
er
innerhalb der UPDATE- bzw.
DELETE-Anweisung verwendet wird.
Die UPDATE-Anweisung ändert und
die DELETE-Anweisung löscht
die
Reihe, auf welcher der Cursor positioniert ist.
Nach
der Ausführung der UPDATE-
bzw. DELETE-Anweisung wird die
Position des Cursors nicht
geändert. Erst die
nächste
FETCH-Anweisung positioniert den
Cursor auf die nächste Reihe
der Treffermenge.
Das
folgende Beispiel zeigt die
Verwendung des Cursors beim
Löschen der Reihen.
Beispiel 16.17
Finden Sie alle Reihen
der Tabelle arbeiten, deren Spalte
m_nr dem eingegebenen Wert entspricht, und löschen Sie sie
anschließend.
IDENTIFICATION DIVISION.
PROGRAM-ID. BSP1617.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL BEGIN DECLARE SECTION
END-EXEC.
77
PRNR PIC X(4) VALUE SPACES.
77
MNR PIC S9(9) COMP.
77
AUFGABE PIC X(15) VALUE SPACES.
EXEC SQL END DECLARE SECTION
END-EXEC.
77 JA-NEIN PIC X.
PROCEDURE
DIVISION.
PERFORM DBOPEN.
PERFORM A100-DECLARE.
PERFORM A200-OPEN.
PERFORM A300-FETCH UNTIL SQLCODE OF SQLCA = 100.
PERFORM A400-CLOSE.
PERFORM DBCLOSE.
STOP RUN.
DBOPEN.
EXEC SQL
CONNECT BEISPIEL
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY
"FEHLER BEIM DB-OEFFNEN"
STOP RUN.
INF99. EXIT.
A100-DECLARE.
DISPLAY
"Geben Sie die Personalnummer an".
ACCEPT MNR.
EXEC SQL
DECLARE crs_arb CURSOR FOR
SELECT
m_nr, pr_nr, aufgabe
FROM arbeiten
WHERE m_nr = :MNR
FOR UPDATE OF pr_nr
END-EXEC.
A200-OPEN.
EXEC SQL
OPEN crs_arb
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
OPEN".
A300-FETCH.
EXEC SQL
FETCH crs_arb
INTO :MNR, :PRNR, :AUFGABE
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
FETCH".
IF SQLCODE OF SQLCA NOT = 100
THEN PERFORM A310-ABFRAGE.
A400-CLOSE.
EXEC SQL
CLOSE crs_arb
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "Fehler in
CLOSE".
A310-ABFRAGE.
DISPLAY MNR, " ",
PRNR, " ", AUFGABE.
DISPLAY "Moechten Sie diese Reihe loeschen
j/n?".
ACCEPT JA-NEIN.
IF JA-NEIN = "j"
THEN PERFORM A311-DELETE.
A311-DELETE.
EXEC SQL
DELETE FROM arbeiten
WHERE CURRENT OF crs_arb
END-EXEC.
DBCLOSE.
EXEC SQL
DISCONNECT
END-EXEC.
In diesem Beispiel - ähnlich wie in Beispiel 16.13 - wird
jede Reihe vor dem Löschen auf dem
Bildschirm angezeigt und
erst nach der expliziten
Bestätigung gelöscht. Mit dieser
Maßnahme wird eine zusätzliche Kontrolle vor dem Löschen
der
Reihen eingeführt.
Das C-Programm in Beispiel
16.18 verhält sich analog
zum
vorherigen Beispiel.
Beispiel 16.18
/* Beispiel 16.18 */
#include <stdio.h>
EXEC SQL
INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
int m_nr;
char pr_nr[5];
char aufgabe[16];
EXEC SQL END DECLARE SECTION;
main()
{ char ja_n[1];
EXEC SQL
WHENEVER SQLERROR
GO TO :fehler;
EXEC SQL
WHENEVER NOT FOUND
GO TO schlies;
EXEC SQL
CONNECT beispiel;
printf("Geben
Sie die Nummer des Mitarbeiters an:\n");
scanf ("%d", &m_nr);
EXEC SQL
DECLARE crs_arb CURSOR FOR
SELECT m_nr , pr_nr, aufgabe
FROM arbeiten
WHERE m_nr = :m_nr
FOR UPDATE OF m_nr;
EXEC SQL
OPEN crs_arb;
for (;;)
{
EXEC SQL
FETCH crs_arb
INTO
:m_nr, :pr_nr, :aufgabe;
printf("%d %s%s\n",m_nr, pr_nr,
aufgabe);
printf("Moechten Sie diese Reihe loeschen:
j/n?\n");
scanf ("%s",&ja_n);
if (strcmp(ja_n,"n"))
{
EXEC SQL
DELETE FROM arbeiten
WHERE CURRENT OF
crs_arb;
}
}
schlies:
EXEC SQL
CLOSE crs_arb;
EXEC SQL
DISCONNECT;
exit(0);
fehler: printf ("Fehler: %d\n",
sqlca.sqlcode);
}
Sowohl die INGRES-Schnittstelle
zu C als auch die zu COBOL
verwendet einen Vorübersetzer, mit
dem dann die eingebetteten
SQL-Programme in
C bzw. COBOL
übersetzt werden. Der
Aufruf des jeweiligen
Vorübersetzers geschieht mittels
des
Betriebssystemkommandos esqlc für C
bzw. esqlcbl für COBOL.
Weil diese beiden Kommandos die
gleiche Syntax haben, wird
nur das Kommando esqlc
beschrieben.
Das Kommando
esqlc sch_liste datei_name
ermöglicht die Übersetzung eines eingebetteten
SQL-Programms
in
C. datei_name ist
der Name der
Datei, die das
eingebettete SQL-Programm enthält. Zu
der sch_liste können
ein
oder mehrere Schalter
gehören, von denen
wir die
wichtigsten erläutern werden.
Der Schalter "-l" schreibt
alle
Fehlermeldungen der
Vorübersetzerphase sowohl in
eine
Ausgabeliste als
auch auf den
Bildschirm. Der Schalter
"-lo" entspricht dem
Schalter "-l", nur
wird zusätzlich
der generierte C-Code auch
in die Ausgabeliste geschrieben.
Mit
dem Schalter "-f
dat_name" wird die
Ausgabe der
Vorübersetzerphase in
die Datei dat_name geschrieben.
Falls
dat_name nicht angegeben wird, erfolgt die Ausgabe auf
die
Standard-Ausgabe. Der Schalter
"-s" veranlaßt die Eingabe des
eingebetteten SQL-Programms von der Standard-Eingabe und
die
Ausgabe des erstellten Codes auf die
Standard-Ausgabe.
In
diesem Abschnitt werden wir
uns einem Thema
widmen,
das
die Programmierung der
Datenbankanwendung wesentlich
beeinflussen kann. Es handelt
sich um allgemeine Hinweise,
die sowohl den Ablauf der Anwendungen
beschleunigen, als auch
helfen können, mögliche Fehlerquellen zu umgehen.
Den
ersten und gleichzeitig wichtigsten Punkt stellt
die
optimale Programmierung von
Datenbankzugriffen
dar. In den Datenbankanwendungen werden
häufig
Datenmanipulationsanweisungen verwendet,
die gleichzeitig
viele Reihen einer Tabelle auswählen bzw. ändern. In solchen
Fällen ist es immer besser, die
Treffermenge aller Reihen mit
einer SQL-Anweisung (SELECT, UPDATE
oder DELETE) festzulegen,
als
für jede Reihe einmal die entsprechende SQL-Anweisung
durchzuführen. Der
Vorteil der ersten
Programmierungsart
ist,
daß die entsprechende SQL-Anweisung eine wesentlich
geringere Anzahl von E/A-Operationen
erfordert und nur einmal
vorübersetzt werden muß.
Das
folgende Beispiel zeigt,
wie man mit
einer
SELECT-Anweisung eine
größere Anzahl von
Reihen einer
Tabelle effizient auswählen
sollte. Für dieses
und drei
folgende Beispiele wird die Beispieldatenbank verwendet, mit
einer zusätzlichen Annahme: Wir gehen davon aus, daß
die
Tabelle mitarbeiter, die
in allen Beispielen benutzt
wird,
insgesamt 100000 Reihen hat, wobei
die Spalte m_nr eindeutige
Datenwerte zwischen 1 und 100000
aufweist.
Beispiel 16.19
Finden Sie Namen und
Vornamen aller Mitarbeiter, deren
Personalnummer vierstellig ist.
IDENTIFICATION
DIVISION.
PROGRAM-ID. BSP1619.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL BEGIN DECLARE SECTION
END-EXEC.
77
MNAME PIC X(20) VALUE SPACES.
77
MVORNAME PIC X(20) VALUE SPACES.
77
VAR1 PIC S9(9) COMP.
EXEC SQL END DECLARE SECTION
END-EXEC.
EXEC SQL INCLUDE SQLCA END-EXEC.
PROCEDURE DIVISION.
A1.
PERFORM DBOPEN.
PERFORM A100-DECLARE.
PERFORM A200-OPEN.
PERFORM A300-FETCH VARYING VAR1 FROM 1000 BY 1
UNTIL VAR1 >
9999.
PERFORM A400-CLOSE.
PERFORM DBCLOSE.
STOP RUN.
DBOPEN.
EXEC SQL
CONNECT BEISPIEL
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "FEHLER BEIM DB-OEFFNEN"
STOP RUN.
A100-DECLARE.
EXEC SQL
DECLARE crs_mit CURSOR FOR
SELECT m_name, m_vorname
FROM mitarbeiter
WHERE m_nr BETWEEN 1000 AND 9999
END-EXEC.
A200-OPEN.
EXEC SQL
OPEN crs_mit
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "FEHLER IN OPEN".
A300-FETCH.
EXEC SQL
FETCH crs_mit
INTO :MNAME, :MVORNAME
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "FEHLER IN FETCH".
IF SQLCODE OF SQLCA NOT = 100 THEN
DISPLAY MNAME,"
",MVORNAME.
A400-CLOSE.
EXEC SQL
CLOSE crs_mit
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "FEHLER IN CLOSE".
DBCLOSE.
EXEC SQL
DISCONNECT
END-EXEC.
In
Abschnitt A100-DECLARE wird der Cursor crs_mit definiert,
mit dem dann alle Reihen, die
die Treffermenge bilden,
mit
einer SELECT-Anweisung ausgewählt
werden.
Das
folgende Beispiel zeigt eine
ineffiziente Art, dieselbe
Aufgabe wie in Beispiel 16.19 zu
lösen.
Beispiel
16.20
IDENTIFICATION DIVISION.
PROGRAM-ID. BSP1620.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL BEGIN DECLARE SECTION
END-EXEC.
77
MNAME PIC X(20) VALUE SPACES.
77
MVORNAME PIC X(20) VALUE SPACES.
77
VAR1 PIC S9(9) COMP.
EXEC SQL END DECLARE SECTION
END-EXEC.
EXEC SQL INCLUDE SQLCA END-EXEC.
PROCEDURE DIVISION.
A1.
PERFORM DBOPEN.
PERFORM A100-SELECT VARYING VAR1
FROM 1000 BY 1
UNTIL VAR1
> 9999.
PERFORM DBCLOSE.
STOP RUN.
DBOPEN.
EXEC SQL
CONNECT BEISPIEL
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "FEHLER BEIM DB-OEFFNEN"
STOP RUN.
A100-SELECT.
EXEC SQL
SELECT m_name, m_vorname
INTO :MNAME :MVORNAME
FROM mitarbeiter
WHERE m_nr = :VAR1
END-EXEC.
IF SQLCODE OF SQLCA < 0 THEN
DISPLAY "FEHLER IN
SELECT".
DISPLAY MNAME, MVORNAME.
DBCLOSE.
EXEC SQL
DISCONNECT
END-EXEC.
Die
Anzahl der E/A-Operationen in Beispiel 16.20
ist
wesentlich höher als in Beispiel
16.19. Zusätzlich dazu
wird
der Abschnitt A100-SELECT
und damit auch die
SELECT
Anweisung 9000 vorübersetzt. Dadurch wird ein Programm, das
einen solchen Teil beinhaltet, wesentlich langsamer als ein
Programm, das, wie in
Beispiel 16.19 gezeigt programmiert
wurde.
Das folgende Beispiel zeigt ein
C-Programm, das identisch mit
Beispiel 16.19 ist und die
effizientere Programmierart in C
zeigt.
Beispiel 16.21
/* Beispel 16.21 */
#include <stdio.h>
EXEC SQL
INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
char
m_name[21];
char m_vorname[21];
int i;
EXEC SQL END DECLARE SECTION;
main()
{
EXEC SQL
WHENEVER SQLERROR
GO TO :fehler;
EXEC SQL
WHENEVER NOT FOUND
GO TO :schlies;
EXEC SQL
CONNECT beispiel;
EXEC SQL
DECLARE crs_mit CURSOR FOR
SELECT
m_name, m_vorname
FROM mitarbeiter
WHERE m_nr BETWEEN 1000 AND 9999;
EXEC SQL
OPEN crs_mit;
for (i=1000; i<=9999; i++)
{
EXEC SQL
FETCH crs_mit INTO :m_name,
:m_vorname;
printf("%s%s\n",
m_name, m_vorname);
}
schlies:
EXEC SQL
CLOSE crs_mit;
EXEC SQL
DISCONNECT;
exit(0);
fehler: printf ("Fehler: %d\n",
sqlca.sqlcode);
}
Die ineffiziente Form dieses
Programms zeigt Beispiel 16.22.
Beispiel 16.22
/* Beispel 16.22 */
#include <stdio.h>
EXEC SQL
INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
char
c_name[21];
char c_vorname[21];
int i;
EXEC SQL END DECLARE SECTION;
main()
{
EXEC SQL
WHENEVER SQLERROR
GO TO :fehler;
EXEC SQL
CONNECT beispiel;
for (i=1000; i<=9999; i++)
{
EXEC SQL
SELECT m_name, m_vorname
INTO :c_name, :c_vorname
FROM mitarbeiter
WHERE m_nr = :i;
printf("%s%s\n",
c_name , c_vorname);
}
EXEC SQL
DISCONNECT;
exit(0);
fehler: printf ("Fehler: %d\n",
sqlca.sqlcode);
}
Zu
gutem Programmierstil gehört
auch die explizite Abfrage,
ob eine Reihe geändert bzw. gelöscht
werden soll.
Wenn
eine Reihe mittels
einer UPDATE- bzw.
einer
DELETE-Anweisung bearbeitet werden soll, ist
es
empfehlenswert, die Datenwerte dieser Reihe am Bildschirm
zuerst anzuzeigen, bevor sie
geändert bzw. gelöscht werden
sollten. Damit gibt man dem Anwender die Möglichkeit, sich
zu vergewissern, ob es sich
tatsächlich um die Reihe handelt,
die er modifizieren will.
Die
Beispiele 16.17 und 16.18 zeigen diesen Programmierstil.
Bevor eine Reihe der Tabelle arbeiten
gelöscht wird, werden
die Datenwerte dieser Reihe am
Bildschirm angezeigt, und erst
gelöscht, wenn der Anwender dies
explizit bestätigt.
In der Projektion einer SELECT-Anweisung ist es möglich, die
Angabe aller
Spaltennamen durch das Zeichen "*" zu ersetzen.
Bei der interaktiven Anwendung
einer SELECT-Anweisung sind
beide Schreibweisen gleich gut.
Dies ist aber nicht bei
den
eingebetteten Anweisungen der
Fall, bei denen
alle
Spaltennamen in
einer SELECT-Anweisung angegeben
sein
sollten.
Die explizite Angabe aller Spaltennamen ist
wichtig, weil
jedes Ändern des Tabellenschemas einen Fehler im Programm
verursachen kann.
In diesem Fall
stimmt die Anzahl
der
Spalten mit der Anzahl der ihnen zugewiesenen Host-Variablen
nicht mehr überein.
Beispiel 16.23 zeigt, wie
die SELECT-Anweisung für
die
Tabelle mitarbeiter in einem COBOL-Programm geschrieben sein
sollte.
Beispiel 16.23
EXEC SQL
SELECT m_nr, m_name, m_vorname, abt_nr
INTO :MNR, :MNAME, :MVORNAME, :ABTNR
FROM mitarbeiter
WHERE m_nr < MINZAHL
END-EXEC.
Alle Aufgaben dieses Kapitels
sollen mit der
Programmiersprache Ihrer Wahl
programmiert werden.
A.16.1 Finden Sie die Aufgabe des Mitarbeiters,
dessen Personal-
und Projektnummer am Bildschirm
eingegeben werden.
A.16.2 Fügen
Sie die Reihe
mit Namen, Vornamen
und der
Personalnummer eines
neuen Mitarbeiters ein.
Die
Mitarbeiterdaten sollen am
Bildschirm eingegeben werden.
A.16.3 Finden Sie die Aufgabe und Projektnummer des
Mitarbeiters
mit der Personalnummer 28559.
A.16.4 Vergleichen Sie die Laufzeiten der
Programme in den
Beispielen 16.19 und 16.20 bzw.
16.21 und 16.22.