.so /z/ing_src/macdoc
.NH 1
.ds RH \f3QUEL\f1
.ds RF \f3\*(yy\f1
.ds CH - % -
.ds LH Anwendung
.ds LF \*(vv
.pn 162
.LP
.bp
.NH 1
.ft B
Anwenderdokumentation
.br
        \*(yy\ 6.3/3 - Teil II
.ft R
.sp 5
.nf
#############################################################
#############################################################
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##      ###   #     #  #####          ######  ######       ##
##       #    ##    # #     #         #     # #     #      ##
##       #    # #   # #               #     # #     #      ##
##       #    #  #  # #  ####         #     # ######       ##
##       #    #   # # #     #         #     # #     #      ##
##       #    #    ## #     #         #     # #     #      ##
##      ###   #     #  #####  ####### ######  ######       ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##        ####### #######   ###   #          #####         ##
##           #    #          #    #         #     #        ##
##           #    #          #    #               #        ##
##           #    #####      #    #          #####         ##
##           #    #          #    #         #              ##
##           #    #          #    #         #              ##
##           #    #######   ###   #######   #######        ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
##                                                         ##
#############################################################
#############################################################

.fi
.bp
.NH 2
.ft B
Anwendung der QUEL *
.ft R
.LP
.sp 10
Dieser Einf\o'u"'hrungskurs beschreibt, wie das \*(yy\ 6.3-DBS
anzuwenden ist.
Sie sollten in der Lage sein, den angegebenen
Beispielen zu folgen und die gleichen Ergebnisse zu erhalten.
Die Datenbank "demo" ist in der ausgelieferten
Vertriebsversion enthalten.
Nach den \o'U"'bungen in diesem Kapitel sind sie in der
Lage die anschliessenden beiden Kapitel besser 
zu verstehen. Es empfiehlt sich auch, das Referenz-Manual
noch einmal gr\o'u"'ndlich zu lesen.
.LP
Die Daten-Manipulations-Sprache, die von 
\*(yy\ 6.3 unterst\o'u"'tzt wird, nennt sich
QUEL (Query Language) bzw. in Kurzform Query.
Eine vollst\o'a"'ndige Information zur QUEL wird
im \*(yy\ 6.3-Referenz-Manual (Teil I) gebracht.
Dieser Kurs beabsichtigt nicht, jedes
Detail von \*(yy\ 6.3 zu ber\o'u"'hren.
Es wird aber versucht, sie zu bef\o'a"'higen,
die QUEL aktiv zu beherrschen und auf dieser
Basis Schritt f\o'u"'r Schritt in die Geheimnisse
von \*(yy\ 6.3 einzusteigen.
.LP
Fangen wir mit dem Eintritt in \*(xx\, dem
Time-Sharing-System, unter dem \*(yy\ 6.3 l\o'a"'uft, an.
Wenn irgend m\o'o"'glich, benutzen sie ein Terminal,
das \o'u"'ber Gross- und Kleinbuchstaben verf\o'u"'gt,
anderenfalls werden sie ein schweres Leben haben.
Wenn sie an einem Terminal arbeiten, das nur
Grossbuchstaben hat, geben
sie "\\\\" anstelle "\\" f\o'u"'r Beispiele dieses
Einf\o'u"'hrungskurses ein.
.LP
Nach Eintritt in das Mehrnutzersystem (Eingabe des "login"-Namens)
wird auf dem Terminal die Bereitschaft mit "%" angezeigt.
(Durch \o'A"'nderung von PS1 im .profile "/mnt/ing_db/.profile" auf
"%" erhalten sie \o'U"'bereinstimmung mit den angef\o'u"'hrten
Beispielen, wobei "%" vom Terminal ausgegeben wird !)
Um \*(yy\ 6.3 zu nutzen, geben sie beispielsweise das Kommando:
.DS L

% quel dt

.DE
.LP
Das veranlasst \*(xx\, die Datenbank "demo" zur
Nutzung durch \*(yy\ 6.3 bereitzustellen.
Nach einigen Sekunden erscheint folgendes:
.DS L

ING_db version 6.3/3 login
Tue Aug 30 14:52:23 1985

ING_db>
*

.DE
.LP
(Sofern sys/etc/dayfile nicht leer ist
bzw. die Ausgabe nicht unterdr\o'u"'ckt wird, wird vor
ING_db> noch
der Inhalt dieses File's angegeben.)
Die ersten beiden Zeilen beinhalten die \*(yy\ 6.3-Version
(in diesem Fall "Version 6.3") und das aktuelle Datum.
Danach folgt die Ausgabe des "dayfile",
das Mitteilungen
- bezogen auf \*(yy\ 6.3 - enth\o'a"'lt.
Das I N G - d b > zeigt an, dass \*(yy\ 6.3
bereit ist, ihre Kommandos anzunehmen.
.LP
Der Monitor
erinnert mit einem Stern ("*") am Zeilenanfang daran,
dass \*(yy\ 6.3
auf eine Eingabe wartet.
.br
Wenn Sie den Monitor zur Ausf\o'u"'hrung der Query
angewiesen haben, erscheint die Ausschrift
Zu Beginn arbeiten wir mit einer Relation "teile", die
folgende Struktur hat:
.DS L

* help teile
* \eg

I N G - d b . . .

Relation:		teile
---------
Besitzer:		ing_db
Tupellaenge:		34
Verfallsdatum:		Tue Apr 26 19:57:10 1988
Tupelanzahl:		13
Speicherstruktur:	HEAP
Relationentyp:		Nutzerrelation

 Domaenname        Typ   Laenge  Schluessel
-------------------------------------------
 tnum        	    i       2
 tname       	    c      20
 farbe       	    c       8
 gewicht     	    i       2
 menge       	    i       2
-------------------------------------------

ING-db:
.DE
.LP
Geben sie das Kommando:
.DS L

* print teile
* \eg

I N G - d b   . . .

.DE
.LP
Die Zeile "print teile" fordert eine Anzeige von
Daten, die in der Datenbank gespeichert sind.
Das "\\g" weist den Monitor zur Ausf\o'u"'hrung der
Query an.
Die Mitteilung
.br
"I N G - d b   . . . "
.br
informiert, dass \*(yy\ 6.3 ihre Query ausf\o'u"'hrt.
Der Ausschrift wird noch der Maschinentyp vorangestellt.
Das Ergebnis sieht dann so aus:
.DS L

Relation: teile


|tnum  |tname               |farbe   |gewich|menge |
|--------------------------------------------------|
|     1|Zentraleinheit      |rosa    |    10|     1|
|     2|Hauptspeicher       |grau    |    20|    32|
|     3|Plattenspeicher     |schwarz |   685|     2|
|     4|Magnetbandspeicher  |schwarz |   450|     4|
|     5|Magnetbaender       |grau    |     1|   250|
|     6|Zeilendrucker       |gelb    |   578|     3|
|     7|Zeilendruckerpapier |weiss   |    15|    95|
|     8|Terminals           |blau    |    19|    15|
|    13|Lochbandleser       |schwarz |   107|     0|
|    14|Lochbandstanzer     |schwarz |   147|     0|
|     9|Konsolpapier        |weiss   |     2|   350|
|    10|Kartenleser         |grau    |   327|     0|
|    11|Kartenstanzer       |grau    |   427|     0|
|--------------------------------------------------|

ING_db:
*

.DE
.LP
Das, was auf Ihrem Terminal angezeigt wurde, ist die "teile"- Relation.
Intuitiv, eine Relation ist nicht mehr, als eine Tabelle
mit Zeilen und Spalten.
.LP
In diesem Fall ist der Name der Relation "teile".
Sie hat f\o'u"'nf Spalten (, wir nennen sie Dom\o'a"'nen,)
bezeichnet mit "tnum" (Teile-Nummer), "tname" (Teile-Bezeichnung),
"farbe", "gewicht" und "menge" (Bestand).
Jede Zeile der Relation (genannt Tupel)
repr\o'a"'sentiert einen Eintrittspunkt (Satz),
der in diesem Fall ein Teil
f\o'u"'r eine Computer-Installation bezeichnet.
Eine Relation kann bis zu 49 Dom\o'a"'nen und eine
im Grunde genommen unbegrenzte Zahl von Tupeln haben.
.LP
Beachten sie, nachdem die Query ausgef\o'u"'hrt ist,
gibt \*(yy\ 6.3
.ft B
"ING_db:"
.ft R
aus, w\o'a"'hrend anfangs nach dem
Eintritt
.ft B
"ING_db>"
.ft R
angezeigt wurde.
Wenn sie eine Query eingeben, legt sie \*(yy\ 6.3
in einem "Arbeitsspeicher" ab.
Wenn sie
eine Query falsch eingegeben haben, k\o'o"'nnen sie mit "\\r",
also "reset" (dh. l\o'o"'schen) den Arbeitsspeicher l\o'o"'schen.
(Sp\o'a"'ter werden wir Wege kennen lernen,
um Fehler zu editieren, so, als
w\o'u"'rden wir die eingegebene Query korrigieren.)
.LP
Jederzeit k\o'o"'nnen sie sich den Arbeitsspeicher
durch Eingabe von "\\p" ansehen.
Versuchen sie "\\p":
.DS L

* \ep
print teile
ING-db:
*

.DE
.LP
Der aktuelle Inhalt des Arbeitsspeichers
wird angezeigt.
Versuchen sie jetzt "\\r":
.DS L

* \er
ING_db>
*

.DE
.LP
Der Arbeitsspeicher ist jetzt leer.
Solange
\*(yy\ 6.3 "ING_db:" ausgibt,
ist der Arbeitsspeicher nicht-leer;
solange \*(yy\ 6.3 "ING_db>" ausgibt, ist er leer.
.LP
Nachdem eine Query ausgef\o'u"'hrt wurde,
gibt \*(yy\ 6.3 normalerweise "ING_db:" aus.
Wenn sie dann eine neue Query eingeben, l\o'o"'scht \*(yy\ 6.3
automatisch die vorhergehende, obwohl
sie nicht nach jeder Query "\\r" eingegeben haben.
Das wird sp\o'a"'ter noch erkl\o'a"'rt.
.LP
Die Verwendung des "retrieve"-Kommandos erlaubt uns,
spezifische Queries \o'u"'ber Relationen zu schreiben.
Als Beispiel wollen wir \*(yy\ 6.3
veranlassen, nur "tname" als Dom\o'a"'ne aus der "teile"-
Relation auszugeben.
Geben sie das Kommando:
.DS L

* range of t is teile
* retrieve (t.tname)
* \eg

I N G - d b   . . .

|tname               |
|--------------------|
|Zentraleinheit      |
|Hauptspeicher       |
|Plattenspeicher     |
|Magnetbandspeicher  |
|Magnetbaender       |
|Zeilendrucker       |
|Zeilendruckerpapier |
|Terminals           |
|Lochbandleser       |
|Lochbandstanzer     |
|Konsolpapier        |
|Kartenleser         |
|Kartenstanzer       |
|--------------------|
13 tuples touched

ING_db:
*

.DE
.LP
Die Ausgabe beschr\o'a"'nkt sich auf die Dom\o'a"'ne
"tname" aus der Relation "teile".
Dazu ben\o'o"'tigten wir zwei Schritte.
Zuerst haben wir eine sogenannte "Tupel-Variable"
deklariert und ihren Bereich der Relation "teile" zugewiesen.
.DS L

range of t is teile
.DE
.LP
Damit ist gemeint, dass der Buchstabe "t" die Relation
"teile" repr\o'a"'sentiert.
Man kann sich das als eine Markierung
vorstellen, die die Relation "teile" eine Stufe
niedriger einordnet.
\*(yy\ 6.3 merkt sich die Verbindung, sodass,
wenn "t" einmal als Bereich \o'u"'ber "teile"
deklariert wurde, eine Wiederholung der Deklaration
nicht notwendig ist.
Das ist, wie wir sp\o'a"'ter sehen werden, \o'u"'blich,
falls wir mit mehr als einer Relation arbeiten.
.LP
Als n\o'a"'chstes benutzten wir das
"retrieve"-Kommando.
Seine Form ist
.DS L

retrieve ( listen sie hier, wonach sie suchen )

.DE
.LP
"t" referenziert durch sich selbst die Relation "teile".
"t.tname" referenziert die Dom\o'a"'ne "tname" der Relation
"teile", sozusagen:
.DS L

retrieve (t.tname)

.DE
meint die Recherche nach der Dom\o'a"'ne
"tname" der Relation "teile".
.LP
Versuchen wir
nach "tname" und "farbe" zu recherchieren:
.DS L

* retrieve t.tname, t.farbe
* \eg

I N G - d b   . . .

2500: syntax error on line 1
last symbol read was: .

ING_db:
*

.DE
.LP
Ungl\o'u"'cklicherweise haben wir einen Fehler gemacht.
\*(yy\ 6.3 teilt uns mit, dass es einen Syntax-Fehler
auf der ersten Zeile der Query gefunden hat.
"Syntax error" bedeutet, dass wir etwas eingegeben
haben, was \*(yy\ 6.3 nicht wiedererkennen bzw. interpretieren
kann.
Der Fehler trat auf Zeile 1 auf.
\*(yy\ 6.3 f\o'u"'hrt einen manchmal undeutlichen
Versuch zur Diagnose des Problems durch.
Sofern m\o'o"'glich, teilt uns \*(yy\ 6.3 mit,
was es gelesen hat, bevor es durcheinander kam.
.LP
In diesem Fall ist der Fehler der, dass die Liste der
Rechercheobjekte
(, die sogenannte "target_list",) in Klammern eingeschlossen
werden muss.
Die korrekte Query ist:
.DS L

* retrieve (t.tname, t.farbe)
* \eg

I N G - d b   . . .

|tname               |farbe   |
|-----------------------------|
|Zentraleinheit      |rosa    |
|Hauptspeicher       |grau    |
|Plattenspeicher     |schwarz |
|Magnetbandspeicher  |schwarz |
|Magnetbaender       |grau    |
|Zeilendrucker       |gelb    |
|Zeilendruckerpapier |weiss   |
|Terminals           |blau    |
|Lochbandleser       |schwarz |
|Lochbandstanzer     |schwarz |
|Konsolpapier        |weiss   |
|Kartenleser         |grau    |
|Kartenstanzer       |grau    |
|-----------------------------|
13 tuples touched

ING_db:
*

.DE
.LP
Sie k\o'o"'nnen durch Hinzuf\o'u"'gung einer
"Qualifikation" an die Query einschr\o'a"'nken,
welche Tupel ausgegeben werden sollen.
Beispielsweise, um die Namen und Farben
nur der Teile zu erhalten, die grau sind,
geben sie ein:
.DS L
* retrieve (t.tname, t.farbe)
* where t.farbe = "grau"
* \eg

I N G - d b   . . .

|tname               |farbe   |
|-----------------------------|
|Hauptspeicher       |grau    |
|Magnetbaender       |grau    |
|Kartenleser         |grau    |
|Kartenstanzer       |grau    |
|-----------------------------|
4 tuples touched

ING-db:
*

.DE
Beachten sie, dass \*(yy\ 6.3 nur die Teile angibt, wo "t.farbe"
gleich "grau" ist.
Beachten sie auch, dass grau in Anf\o'u"'hrungsstrichen ("grau")
stehen muss.
Das ist notwendig.
Der einzige Weg, \*(yy\ 6.3 zur Erkennung von Zeichenketten zu
veranlassen (z.B. Worte), ist, sie in 
Anf\o'u"'hrungsstriche einzuschliessen.
.LP
Was ist, wenn wir die Bezeichnungen der Teile wissen wollen,
die grau oder rosa sind?
Wir brauchen nur an die vorhergehende Query den
Ausdruck
.DS L

or t.farbe = "rosa"

.DE
anh\o'a"'ngen.
Erinnern sie sich, wie auch immer,
wenn die n\o'a"'chste Zeile eingegeben wurde,
beginnt \*(yy\ 6.3 eine neue Query und wird automatisch
den Arbeitsspeicher l\o'o"'schen.
Der Arbeitsspeicher kann nur
.ft B
gerettet
.ft R
werden, wenn die n\o'a"'chste Zeile mit einem solchen Kommando
wie "\\p" oder "\\g" beginnt.
(Es gibt noch andere M\o'o"'glichkeiten, wie wir
sp\o'a"'ter sehen werden.)
Wenn so ein Kommando eingegeben wird,
ist die vorhergehende Query gerettet und
anschliessend kann an diese Query angeh\o'a"'ngt werden.
.LP
Wir geben ein:
.DS L

* \ep
retrieve (t.tname, t.farbe)
where t.farbe = "grau"
ING-db:
*

.DE
.LP
Sie k\o'o"'nnen die vorhergehende Query sehen.
Jetzt geben sie ein:
.DS L

* or t.farbe = "rosa"
*

.DE
\*(yy\ 6.3 h\o'a"'ngt die letzte Zeile an das Ende der Query an.
Sie k\o'o"'nnen sich davon \o'u"'berzeugen, indem sie
den Arbeitsspeicher ausgeben:
.DS L

* \ep
retrieve (t.tname, t.farbe)
where t.farbe = "grau"
or t.farbe = "rosa"
ING-db:
*

.DE
Jetzt starten wir die Query:
.DS L

* \eg

I N G - d b   . . .

|tname               |farbe   |
|-----------------------------|
|Zentraleinheit      |rosa    |
|Hauptspeicher       |grau    |
|Magnetbaender       |grau    |
|Kartenleser         |grau    |
|Kartenstanzer       |grau    |
|-----------------------------|
5 tuples touched

ING-db:
*
.DE
.LP
Die Regeln dazu, wann der Arbeitsspeicher gel\o'o"'scht
ist, m\o'o"'gen anfangs etwas verwirrend erscheinen.
Im Allgemeinen wird \*(yy\ 6.3 genau das tun,
was sie erwarten, ohne dass sie viel daran denken.
.LP
Wir haben die verwendeten Qualifikationen "or" und "=" gesehen.
Im Allgemeinen kann eine der folgenden verwendet werden:

.DS L
      and
      or
      not
      =	        (equal)
      !=        (not equal)
      >         (greater than)
      >=        (greater than or equal)
      <         (less than)
      <=        (less than or equal)
.DE
.LP
Die Wertigkeit bestimmt sich in der Reihenfolge,
wie die Qualifikationen angegeben sind (d.h. von links nach rechts).
Klammern k\o'o"'nnen verwendet werden,
um Zusammenh\o'a"'nge in der gew\o'u"'nschten
Reihenfolge zu gruppieren.
.LP
\*(yy\ 6.3 kann Berechnungen mit den, in der
Relation gespeicherten Daten ausf\o'u"'hren.
Beispielsweise beinhaltet die Relation
"teile" den Bestand und das Gewicht f\o'u"'r jedes
Tupel.
Wir m\o'o"'chten das Gesamtgewicht f\o'u"'r
jede Gruppe von Teilen wissen (,d.h. Gewicht multipliziert
mit Bestand).
.LP
Um die Bezeichnung, die Teile-Nummer und das
Gesamtgewicht f\o'u"'r jedes Teil zu erhalten,
geben wir ein:
.DS L

* retrieve (t.tname, t.tnum, t.menge * t.gewicht)
* \eg

I N G - d b   . . .

2500: syntax error on line 1
last symbol read was: *

ING_db:
*

.DE
Ein anderer Fehler!
Das Problem besteht darin, dass nach Ausf\o'u"'hrung
einer Rechnung \*(yy\ 6.3 nicht weiss, wie es die entstandene
Dom\o'a"'ne bei der Ausgabe bezeichnen soll.
F\o'u"'r eine einfache Dom\o'a"'ne
nutzt \*(yy\ 6.3 den Dom\o'a"'nen-Namen als Titel
(\o'U"'berschrift in der Kopfzeile).
Wie auch immer, sie m\o'u"'ssen eine neue Dom\o'a"'ne
gr\o'u"'nden, um den Titel zu spezifizieren:
.DS L

	tot = t.menge * t.gewicht

.DE
Die allgemeine Form ist:
.DS L

	title = expression

.DE
Zum Beispiel:
.DS L

	name = t.tname
	berechnung = t.gewicht / 2000 * (t.menge + 2)

.DE
Wir wollen uns noch mit dem Fehler, der eine Korrektur
der Query erfordert, besch\o'a"'ftigen.
Solange die erste Zeile nach einer Query
nicht mit "\\p" oder "\\g" beginnt, wird
\*(yy\ 6.3 automatisch den Arbeitsspeicher l\o'o"'schen
und die vorhergehende Query ist f\o'u"'r
uns verloren.
.DS L
* retrieve (t.tname, t.tnum, tot=t.menge * t.gewicht)
\eg

I N G - d b   . . .

|tname               |tnum  |tot   |
|----------------------------------|
|Zentraleinheit      |     1|    10|
|Hauptspeicher       |     2|   640|
|Plattenspeicher     |     3|  1370|
|Magnetbandspeicher  |     4|  1800|
|Magnetbaender       |     5|   250|
|Zeilendrucker       |     6|  1734|
|Zeilendruckerpapier |     7|  1425|
|Terminals           |     8|   285|
|Lochbandleser       |    13|     0|
|Lochbandstanzer     |    14|     0|
|Konsolpapier        |     9|   700|
|Kartenleser         |    10|     0|
|Kartenstanzer       |    11|     0|
|Hauptspeicher       |     2|   640|
|Kartenleser         |    10|     0|
|----------------------------------|
13 tuples touched

ING_db:
*

.DE
Ausser der Multiplikation unterst\o'u"'tzt \*(yy\ 6.3
bspw. die Operatoren
.DS
+    Addition
-    Subtraktion (und Bin\o'a"'rnegation)
/    Division
*    Multiplikation
**   Exponentation (z.B. 3**10)
abs  Absolutwert    (z.B. abs(p.qoh - 50) )
mod  Modulo-Division (Divisionsrest)
.DE
und einige andere mehr.
\o'U"'berpr\o'u"'fen sie bitte im \*(yy\ 6.3-Referenz-Manual diese
kurze Darstellung und vervollst\o'a"'ndigen sie,
was unterst\o'u"'tzt wird.
.LP
Wenn wir anschliessend die Teile-Nummer 2 oder 10
ausw\o'a"'hlen wollen, dann k\o'o"'nnen wir die Qualifikation
.DS L

	where t.tnum = 2 or t.tnum = 10
.DE
angeben.
.LP
.ft B
VORSICHT:
.ft R
Wenn wir gerade damit beginnen "where t.tnum .... "
einzugeben, wird \*(yy\ 6.3 das als Beginn einer neuen Query
verstehen und den  Arbeitsspeicher
l\o'o"'schen.
Um das zu umgehen, k\o'o"'nnen sie "\\p" eingeben und ein 
anschliessendes "append"-Kommando garantiert
("\\a" (append)), dass, was immer sie eingeben, dem Inhalt des
Arbeitsspeichers hinzugef\o'u"'gt wird.
Dieses Kommando wird nur ben\o'o"'tigt, nachdem
zwischenzeitlich eine Query zur Ausf\o'u"'hrung 
angewiesen wurde.
Zum anderen werden Daten automatisch hinzugef\o'u"'gt.
Versuchen sie folgendes:
.DS L

* \ea
* where t.tnum = 2 or t.tnum = 10
* \eg

I N G - d b   . . .

|tname               |tnum  |tot   |
|----------------------------------|
|Hauptspeicher       |     2|   640|
|Kartenleser         |    10|     0|
|----------------------------------|
2 tuples touched

ING_db:
*

.DE
Um alle Teile-Nummern gr\o'o"'sser als 2 und kleiner,
gleich 10 auszuw\o'a"'hlen, folgendes:
.DS L

* retrieve (t.tname, t.tnum, tot=t.menge * t.gewicht)
* where t.tnum > 2 and t.tnum <= 10
* \eg

I N G - d b   . . .

|tname               |tnum  |tot   |
|----------------------------------|
|Plattenspeicher     |     3|  1370|
|Magnetbandspeicher  |     4|  1800|
|Magnetbaender       |     5|   250|
|Zeilendrucker       |     6|  1734|
|Zeilendruckerpapier |     7|  1425|
|Terminals           |     8|   285|
|Konsolpapier        |     9|   700|
|Kartenleser         |    10|     0|
|----------------------------------|
8 tuples touched

 ING_db:
*

.DE
.LP
Nun wollen wir Unterst\o'u"'tzung, um die
vorhergehende Query so zu \o'a"'ndern, dass sie die 
Ergebnisse der Teile-Nummern zwischen 5 und 10,
anstelle von 2 und 10 liefert.
Sie w\o'a"'ren sicher ver\o'a"'rgert, wenn
sie nur ein Zeichen \o'a"'ndern m\o'u"'ssten, sollen
aber daf\o'u"'r die ganze Query nocheinmal eingeben.
Deshalb gestattet
\*(yy\ 6.3 die Verwendung des \*(xx\-Texteditors,
um Korrekturen und/oder Hinzuf\o'u"'gungen
zu Ihrem Arbeitsspeicher vorzunehmen.
Jederzeit k\o'o"'nnen sie "\\e" eingeben,
der \*(yy\ 6.3-Monitor schreibt ihren Arbeitsspeicher auf ein
File und ruft das \*(xx\-Programm "ed".
Zum Beispiel:
.DS L

* \ee
>>ed
83

.DE
Die ">>ed"-Mitteilung sagt Ihnen, dass sie jetzt den
Editor nutzen.
Die Zahl 83 ist die Anzahl der Bytes in Ihrem Arbeitsspeicher.
.LP
Wir k\o'o"'nnen nun die Query editieren und
2 auf 5 \o'a"'ndern.
Die \*(xx\-Dokumentation
(Manual 1, "ed") beschreibt, wie der
Texteditor zu nutzen ist.
Aber wir wollen lieber etwas doppelt bringen und zeigen
einige Editor-Kommandos, um zu illustrieren,
wie zu editieren ist:
.DS L

1p
retrieve (t.tname,t.tnum,tot = t.menge * t.gewicht)
2p
where t.tnum > 2 and t.tnum <= 10
s/2/5/p
where t.tnum > 5 and t.tnum <= 10
w
83
q
*

.DE
Ganz kurz, was ereignet sich.
"1p" und "2p" gibt die Zeilen 1 und 2 aus.
"s/2/5/p" ersetzt 5 durch 2 auf der aktuellen Zeile
(Zeile 2) und gibt diese Zeile anschliessend aus.
"w" schreibt die Query zur\o'u"'ck in den \*(yy\ 6.3-Arbeitsspeicher.
.LP
Innerhalb des Editors k\o'o"'nnen sie alle "ed"-Kommandos,
ausser "e" (,es ver\o'a"'ndert den File-Namen) verwenden.
Wenn sie mit "quit" den Editor (q-Kommando) verlassen,
sind sie wieder zum Monitor zur\o'u"'ckgekehrt.
Beachten sie, dass vor einem "q"-Kommando ein
"w"-Kommando gegeben werden muss,
um den Arbeitsspeicher zur\o'u"'ckzuschreiben
(Aber keine Angst! Der Editor erinnert sie daran, wenn
sie es vergessen haben!).
.LP
Um sich zu vergewissern, dass die Query korrekt ist, und um
sie auszuf\o'u"'hren, geben sie ein:
.DS L
* \ep\eg
retrieve (t.tname,t.tnum,tot = t.menge * t.gewicht)
where t.tnum > 5 and t.tnum <= 10

I N G - d b   . . .


|tname               |tnum  |tot   |
|----------------------------------|
|Zeilendrucker       |     6|  1734|
|Zeilendruckerpapier |     7|  1425|
|Terminals           |     8|   285|
|Konsolpapier        |     9|   700|
|Kartenleser         |    10|     0|
|----------------------------------|
5 tuples touched

ING_db:
*

.DE
.LP
Wir nehmen an, dass ihr
Interesse, soweit es die Relation "teile" betrifft, ersch\o'o"'pft
ist. Sehen wir uns deshalb 
eine neue Relation, genannt "lieferung" an.
Geben sie ein:
.DS L

* print lieferung
* \eg

I N G - d b   . . .


lieferung relation

|lnum  |tnum  |bnum  |liefdat |menge |
|------------------------------------|
|   475|     1|  1001|73-12-31|     1|
|   475|     2|  1002|74-05-31|    32|
|   475|     3|  1001|73-12-31|     2|
|   475|     4|  1002|74-05-31|     1|
|   122|     7|  1003|75-02-01|   144|
|   122|     7|  1004|75-02-01|    48|
|   122|     9|  1004|75-02-01|   144|
|   440|     6|  1001|74-10-10|     2|
|   241|     4|  1001|73-12-31|     1|
|    62|     3|  1002|74-06-18|     3|
|   475|     2|  1001|73-12-31|    32|
|   475|     1|  1002|74-07-01|     1|
|     5|     4|  1003|74-11-15|     3|
|     5|     4|  1004|75-01-22|     6|
|    20|     5|  1001|75-01-10|    20|
|    20|     5|  1002|75-01-10|    75|
|   241|     1|  1005|75-06-01|     1|
|   241|     2|  1005|75-06-01|    32|
|   241|     3|  1005|75-06-01|     1|
|    67|     4|  1005|75-07-01|     1|
|   999|    10|  1006|76-01-01|   144|
|   241|     8|  1005|75-07-01|     1|
|   241|     9|  1005|75-07-01|   144|
|------------------------------------|

 ING_db:
*

.DE
Die "lieferung"-Relation beinhaltet "lnum" (, die
Lieferer-Nummer),
"tnum" (, die Teile-Nummer des gelieferten Teils),
"bnum" (, die Bestellnummer),
"liefdat" (, das Lieferdatum)
und "menge" (, die Liefermenge).
.LP
Um herauszufinden, welche Teile von der Lieferer-Nummer 122 
geliefert werden, geben sie ein:
.DS L

* retrieve (l.tnum) where l.lnum = 122
* \eg

I N G - d b   . . .

2109: line 1, Variable 'l' not declared in RANGE statement

ING_db:
*

.DE
Wir haben die Tupel-Variable "l"
(, d.h. l.tnum) verwendet, ohne \*(yy\ 6.3 mitzuteilen, was
"l" repr\o'a"'sentiert.
Wir haben die Bereichsdeklaration "range" vergessen.
Korrigieren wir die Query wie folgt:
.DS L

* range of l is lieferung
* retrieve (l.tnum) where l.lnum = 122
* \eg

I N G - d b   . . .


|tnum  |
|------|
|     7|
|     7|
|     9|
|------|
3 tuples touched

ING_db:
*

.DE
Die Lieferer-Nummer 122 liefert die Teile-Nummern 7, 7 und 9.
Beachten sie, dass 7 zweimal aufgelistet wurde.
Bei der Recherche nach Tupeln \o'u"'ber das Terminal ist es
effizienter f\o'u"'r \*(yy\ 6.3,
.ft B
nicht
.ft R
nach doppelten Tupeln suchen zu 
m\o'u"'ssen.
\*(yy\ 6.3 ist in der Lage doppelte Tupel zu l\o'o"'schen.
Wir wollen darauf sp\o'a"'ter zur\o'u"'ckkommen.
.LP
Wir wissen jetzt, dass der Lieferer 122 die
Teile-Nummern 7 und 9 liefert.
Wenn sie diese Query nicht einige hundert
mal abarbeiten, wissen sie sicher nicht,
was mit den Teile-Nummern 7 und 9 gemeint ist.
Wir k\o'o"'nnen das einfach herausfinden,
wenn wir die Query
.DS L

* retrieve (t.tname) where t.tnum = 7 or
* t.tnum = 9
* \eg

I N G - d b   . . .

|tname               |
|--------------------|
|Zeilendruckerpapier |
|Konsolpapier        |
|--------------------|
2 tuples touched

 ING_db:
*

.DE
abarbeiten.
Nach zwei Queries wissen wir die Teile-Bezeichnung
der Teile, die der Lieferer 122 liefert.
Wir k\o'o"'nnen dasselbe in einer Query erreichen,
wenn wir fragen:
.DS L

* retrieve (t.tname) where t.tnum = l.tnum
* and l.lnum = 122
* \eg

I N G - d b   . . .


|tname               |
|--------------------|
|Zeilendruckerpapier |
|Zeilendruckerpapier |
|Konsolpapier        |
|--------------------|
3 tuples touched

 ING_db:
*

.DE
Beachten sie, dass "Zeilendruckerpapier" doppelt vorkommt.
Schauen sie sich schliesslich die Query an.
Sie bemerken, dass die Dom\o'a"'ne "tnum"
sowohl in der Relation
"teile", als auch in "lieferung" vorkommt.
Mit der Aussage "t.tnum = l.tnum" verbinden wir logisch
die beiden Relationen.
.LP
Um alle Lieferer, die die Zentraleinheit
liefern, zu finden,
folgende Unterst\o'u"'tzung.
Wir wissen, wie wir nach "l.lnum" recherchieren.
Wir m\o'o"'chten aber nur jene "l.lnum"'s wissen, wo die korrespondierende
"l.tnum" gleich der Teile-Nummer der Zentraleinheit
ist.
.LP
Wenn wir den "t.tname" finden, der gleich "Zentraleinheit"
ist, dann haben wir die korrekte Teile-Nummer "t.tnum".
Schliesslich m\o'o"'chten wir "l.tnum = t.tnum",
die Query lautet:
.DS L

* retrieve (l.lnum) where
* l.tnum = t.tnum and t.tname = "Zentraleinheit"
* \eg

I N G - d b   . . .

|lnum  |
|------|
|   475|
|   475|
|   241|
|------|
3 tuples touched

 ING_db:
*

.DE
Wir wollen die Relationen "teile" und "lieferung" 
verlassen und etwas anderes probieren.
Zuerst k\o'o"'nnen wir feststellen, welche anderen
Relationen die Datenbank besitzt, wenn wir eingeben:
.DS L

* help \eg
I N G - d b   . . .
help \eg
K1630 / EVK Olbernhau - k 1630 / DBA ing_db
DB nicht parallel verwendbar
keine QRYMOD-Unterstuetzung
Seitengroesse 1024 Byte

 Relation          Besitzer      Typ
----------------------------------------------
 attribute         ing_db        Systemkatalog
 relation          ing_db        Systemkatalog
 indexes           ing_db        Systemkatalog
 integrities       ing_db        Systemkatalog
 lager             ing_db        Systemkatalog
 personal          ing_db        Nutzerkatalog
 lieferant         ing_db        Systemkatalog
 abt               ing_db        Systemkatalog
 teile             ing_db        Nutzerkatalog
 artikel           ing_db        Systemkatalog
 protect           ing_db        Systemkatalog
 lieferung         ing_db        Nutzerkatalog
 tree              ing_db        Systemkatalog
----------------------------------------------

ING-db:
*

.DE
Schauen wir uns die Relation "personal" an.
Sofern wir nichts \o'u"'ber die Relation wissen,
k\o'o"'nnen wir das "help"-Kommando nutzen, um etwas
dar\o'u"'ber zu erfahren.
Geben sie ein:
.DS L

* help personal
* \eg

I N G - d b   . . .

relation:               personal
---------
Besitzer:               ing_db
Tupellaenge:            30
Verfallsdatum:          Tue Apr 26 11:01:30 1988
Tupelanzahl:            25
Speicherstruktur:       HEAP
Relationentyp:          Nutzerrelation

 Domaenenname    Typ   Laenge  Schluessel.
 ----------------------------------------
 num               i       2
 name              c      20
 gehalt            i       2
 leiter            i       2
 gebdat            i       2
 einstdat          i       2
 ----------------------------------------

ING_db:
* 

.DE
Das "help"-Kommando listet \o'U"'bersichtsinformationen
zur Relation "personal" aus,
weiterhin zu jedem Attribut, seinem
Typ und seiner L\o'a"'nge.
.LP
\*(yy\ 6.3 unterst\o'u"'tzt drei Datentypen: Integerzahlen,
Gleitkommazahlen und Zeichenketten.
Zeichenketten-Dom\o'a"'nen k\o'o"'nnen von 1 bis 255 Zeichen
lang sein.
Integer-Dom\o'a"'nen k\o'o"'nnen 1, 2, oder 4 Bytes lang sein.
Das bedeutet, dass Integerzahlen einen Wertebereich von
127, \%32767 und \%2147483647 maximal annehmen k\o'o"'nnen.
Gleitkommazahlen k\o'o"'nnen entweder 4 oder 8 Bytes lang sein.
Beide erhalten einen Maximalwert von \o'u"'ber 10**38;
mit 7 oder 17 Ziffern genauer Abbildung.
.LP
Um alle Dom\o'a"'nen anzusehen, k\o'o"'nnen wir das "print"-Kommando
oder das "retrieve"-Kommando nutzen
und geben jede Dom\o'a"'ne in der "target_list" an.
\*(yy\ 6.3 verschafft uns einen Weg, mit wenig Arbeitsaufwand,
das zu realisieren.
Versuchen sie folgendes:
.DS L

* range of p is personal
* retrieve (p.all)
* \eg

I N G - d b   . . . 

|num   |name                |gehalt|leiter|gebdat|einstd|
|-------------------------------------------------------|
|   157|Schmidt, Petra      |  1200|   199|  1940|  1960|
|  1110|Kayser, Helmut      |   600|    33|  1952|  1973|
|    35|Loda, Dieter        |   500|    32|  1952|  1974|
|   129|Thoms, Rolf         |  1000|   199|  1941|  1962|
|    13|Wunsch, Peter-Paul  |   900|   199|  1928|  1958|
|   215|Mueller, Ernst      |   700|    10|  1950|  1971|
|    55|Malter, Juergen     |  1200|   199|  1920|  1969|
|    26|Schneider, Peter    |  1300|   199|  1930|  1970|
|    98|Weise, Juergen      |   900|   199|  1935|  1969|
|    32|Heine, Rolf         |   905|   199|  1929|  1967|
|    33|Ernst, Eva          |  1010|   199|  1931|  1963|
|   199|Gruene, Peter       |  1700|     0|  1920|  1952|
|  4901|Baum, Klaus         |   837|    32|  1956|  1975|
|   843|Schmidt, Hermann    |  1120|    26|  1936|  1956|
|  2398|Warnke, Peter       |   788|    26|  1940|  1959|
|  1639|Maerz, Udo          |  1116|    55|  1947|  1970|
|  5119|Mueller, Petra      |  1362|    55|  1939|  1963|
|    37|Neumann, Inge       |  1198|    26|  1950|  1974|
|  5219|Weber, Franz        |  1337|    33|  1944|  1959|
|  1523|Zeidler, Fritz      |  1686|   129|  1928|  1949|
|   430|Moser, Otto         |  1567|   129|  1938|  1959|
|   994|Schulze, Ernst      |  1564|   129|  1944|  1970|
|  1330|Fleischer, Karl     |   877|    13|  1952|  1971|
|    10|Rose, Peter         |  1590|   199|  1927|  1953|
|    11|Rose, Petra         |  1206|     0|  1931|  1951|
|-------------------------------------------------------|
25 tuples touched

ING_db:
*

.DE
"all" ist ein Schl\o'u"'sselwort, das bei
\*(yy\ 6.3 angewendet wird, um alle Dom\o'a"'nen zu erhalten.
F\o'u"'r die Dom\o'a"'nen ist eine besondere Reihenfolge 
nicht sichergestellt.
Die vorhergehende Query ist \o'a"'quivalent zu:
.DS L

	range of p is personal
	retrieve (p.num, p.name, p.gehalt, p.leiter
		p.gebdat, p.einstdat)

.DE
Wir wollen nach dem Gehalt von Peter Wunsch recherchieren.
An diesem Punkt ist es g\o'u"'nstig,
\o'u"'ber Gross- und Kleinbuchstaben zu verf\o'u"'gen.
Wenn sie an einem Grossbuchstaben-Terminal arbeiten,
geben sie einen einfachen "\\" vor jenen Buchstaben, die
sie in Grossbuchstaben umwandeln wollen.
Damit m\o'u"'sste an einem Grossbuchstaben-Terminal
"\\WUNSCH, \\PETER" eingegeben werden.
Wenn sie an einem Gross-/Kleinbuchstaben-Terminal
arbeiten, benutzen sie die Umschalttaste (u.U. auch SHIFT)
um Grossbuchstaben zu schreiben.
.LP
Starten sie die Query:
.DS L

* retrieve (p.name,p.gehalt)
* where p.name = "Wunsch, Peter"
* \eg

I N G - d b   . . .


|name                |gehalt|
|---------------------------|
|---------------------------|

ING_db:
*

.DE
Das Ergebnis ist leer.
Es gibt keinen "p.name", der die Qualifikation erf\o'u"'llt.
Das befremdet, weil wir wissen, dass es einen Peter Wunsch gibt.
Jedoch weiss \*(yy\ 6.3 nicht, dass "Peter-Paul"
und "Peter" semantisch das Gleiche ist.
.LP
Um in dieser Situation die korrekte Antwort
zu erhalten, m\o'u"'ssen sie die speziellen
"pattern matching"-Zeichen (Vergleichsmuster),
die \*(yy\ 6.3 bereith\o'a"'lt, verwenden.
Ein solches Zeichen ist "*".
Es ist irgendeiner Zeichenkette von 0 bis mehreren Zeichen
ebenb\o'u"'rtig.
Versuchen sie es:
.DS L

* retrieve (p.name,p.gehalt)
* where p.name = "Wunsch, P*"
* \eg

I N G - d b   . . .


|name                |gehalt|
|---------------------------|
|Wunsch, Peter-Paul  |   900|
|---------------------------|
1 tuples touched

ING_db:
*

.DE
.LP
Probieren wir damit etwas anderes.
.DS L

* retrieve (p.name, p.gehalt) where p.name = "Rose, P*"
* \eg

I N G - d b   . . .

|name                |gehalt|
|---------------------------|
|Rose, Peter         |  1590|
|Rose, Petra         |  1206|
|---------------------------|
2 tuples touched

ING-db:
*
.DE
Im ersten Fall ersetzt "*" die Zeichenkette "eter" und
im zweiten Fall "etra".
.LP
Hier ein anderes Beispiel.
Finden sie die Geh\o'a"'lter der
Personen, deren Vorname "Peter" ist:
.DS L

* retrieve (p.name,p.gehalt)
* where p.name = "*, Peter*"
* \eg

I N G - d b   . . .

|name                |gehalt|
|---------------------------|
|Wunsch, Peter-Paul  |   900|
|Schneider, Peter    |  1300|
|Gruene, Peter       |  1700|
|Warnke, Peter       |   788|
|Rose, Peter         |  1590|
|---------------------------|
5 tuples touched

 ING_db:
*

.DE
Beachten sie, wenn wir nach p.name = "*, Peter"
gefragt h\o'a"'tten, w\o'a"'re das 1. Tupel nicht
ausgew\o'a"'hlt worden.
Ebenso ignoriert
\*(yy\ 6.3 "blanks"
in irgendeinem Zeichenkettenvergleich,
egal ob sie "pattern matching" anwenden oder nicht.
Das bedeutet, dass die folgenden
Varianten alle das gleiche Ergebnis bringen:
.DS L

	p.name = "Rose,Peter"
	p.name = "Rose,   Peter   "
	p.name = "R o s e,Peter"

.DE
Einzelne Zeichen oder Bereiche von Zeichen k\o'o"'nnen
in eckige Klammern ([]) eingeschlossen werden.
Zum Beispiel, finde alle Personen, deren Namen mit
"B" bis "F" beginnen:
.DS L

* retrieve (p.name,p.gehalt)
* where p.name = "[B-F]*"
* \eg

I N G - d b   . . .

|name                |gehalt|
|---------------------------|
|Ernst, Eva          |  1010|
|Baum, Klaus         |   837|
|Fleischer, Karl     |   877|
|---------------------------|
3 tuples touched

ING_db:
*

.DE
Beachten sie, dass die letzte Query auch auf einem
anderen Weg realisiert werden k\o'o"'nnte:
.DS L

* retrieve (p.name,p.gehalt)
* where p.name >"A*" and p.name <"G*"
* \eg

I N G - d b . . .

|name                |gehalt|
|---------------------------|
|Ernst, Eva          |  1010|
|Baum, Klaus         |   837|
|Fleischer, Karl     |   877|
|---------------------------|
3 tuples touched

 ING_db:
*

.DE
Die beiden Ergebnisse sind identisch;
jedoch ist der zweite Weg in der Ausf\o'u"'hrung
f\o'u"'r \*(yy\ 6.3 effizienter.
.LP
Es gibt drei Typen von "pattern matching"-Konstruktionen.
Alle drei Typen k\o'o"'nnen in einer Kombination f\o'u"'r
Zeichenketten-Vergleiche genutzt werden.
Das sind:

.IP * 5
\o'A"'quivalent zu einer beliebig langen Zeichenkette;
.IP ? 5
\o'A"'quivalent zu einem Zeichen (nicht "blank")
.IP [] 5
Kann irgendein Zeichen \o'u"'berdecken, das in
Klammern eingeschlossen ist.
Wenn zwei Zeichen durch Binde\%strich (-) getrennt werden,
dann wird jedes Zeichen, das zwischen
beiden in der alphabetischen Folge stehen w\o'u"'rde
\o'u"'berdeckt.
.RE
.LP
Die spezielle Bedeutung der "pattern matching"-Zeichen
kann durch die Kaschierung
mit "\\" aufgehoben werden.
Damit referenziert "\\*" nur das Zeichen
"*".
.LP
Wir wenden uns nun den Aggregat-Operatoren,
die \*(yy\ 6.3 unterst\o'u"'tzt, zu.
Sie bef\o'a"'higen den Nutzer, Berechnungen auf
Dom\o'a"'nen einer Relation vorzunehmen.
Zum Beispiel ist einer dieser Aggregat-Operatoren Durchschnitt (avg)
="average".
Um das durchschnittliche Gehalt f\o'u"'r alle
Angestellten zu berechnen, geben wir ein:
.DS L

* retrieve (dgehalt=avg(p.gehalt))
* \eg

I N G - d b   . . .


|dgehalt   |
|----------|
|  1126.520|
|----------|
1 tuples touched

ING_db:
*

.DE
Der Name "dgehalt"
ist willk\o'u"'rlich, aber notwendig;
\*(yy\ 6.3 ben\o'o"'tigt 
.ft B
einen
.ft R
Namen
f\o'u"'r irgend\%einen Ausdruck in der "target_list"
(anders als f\o'u"'r eine einfache Dom\o'a"'ne).
.LP
Wir k\o'o"'nnen auch das niedrigste (Minimum) und h\o'o"'chste (Ma\%ximum)
Gehalt finden:
.DS L

* retrieve (mingeh=min(p.gehalt),maxgeh=max(p.gehalt))
* \eg

I N G - d b   . . .


|mingeh|maxgeh|
|-------------|
|   500|  1700|
|-------------|
1 tuples touched

ING_db:
*

.DE
Wenn wir die Namen der Angestellten wissen wollen, die das 
niedrigste und h\o'o"'chste Gehalt beziehen, dann
m\o'u"'sste die Query lauten:
.DS L

* retrieve (p.name, p.gehalt)
* where p.gehalt = min(p.gehalt) or p.gehalt = max(p.gehalt)
* \eg

I N G - d b   . . .

|name                |gehalt|
|---------------------------|
|Loda, Dieter        |   500|
|Gruene, Peter       |  1700|
|---------------------------|
2 tuples touched

ING_db:
* 

.DE
\*(yy\ 6.3 unterst\o'u"'tzt folgende Aggregat-Operatoren:
.DS L

	count  Z\o'a"'hle Tupel
	min    Minimum der Dom\o'a"'ne
	max    Maximum der Dom\o'a"'ne
	avg    Berechne Durchschnitt
	sum    Summiere Tupel entsprechend Dom\o'a"'ne
	any    logischer Wert entsprechend Qualifikation

.DE
Wir wollen jetzt eine Query vorstellen, die je Angestelltem
das Durch\%schnittsgehalt \o'u"'ber alle Angestellten
auslistet:
.DS L

* retrieve (p.name,pergeh=avg(p.gehalt))
* \eg

I N G - d b   . . .

|name                |pergeh    |
|-------------------------------|
|Schmidt, Petra      |  1126.520|
|Kayser, Helmut      |  1126.520|
|Loda, Dieter        |  1126.520|
|Thoms, Rolf         |  1126.520|
|Wunsch, Peter-Paul  |  1126.520|
|Mueller, Ernst      |  1126.520|
|Malter, Juergen     |  1126.520|
|Schneider, Peter    |  1126.520|
|Weise, Juergen      |  1126.520|
|Heine, Rolf         |  1126.520|
|Ernst, Eva          |  1126.520|
|Gruene, Peter       |  1126.520|
|Baum, Klaus         |  1126.520|
|Schmidt, Hermann    |  1126.520|
|Warnke, Peter       |  1126.520|
|Maerz, Udo          |  1126.520|
|Mueller, Petra      |  1126.520|
|Neumann, Inge       |  1126.520|
|Weber, Franz        |  1126.520|
|Zeidler, Fritz      |  1126.520|
|Moser, Otto         |  1126.520|
|Schulze, Ernst      |  1126.520|
|Fleischer, Karl     |  1126.520|
|Rose, Peter         |  1126.520|
|Rose, Petra         |  1126.520|
|-------------------------------|
25 tuples touched
ING_db:
*

.DE
Ein Aggregat-Operator erzeugt immer einen einfachen Wert.
Um die letzte Query auszuf\o'u"'hren, bildet
\*(yy\ 6.3 das Durch\%schnittsgehalt zun\o'a"'chst zu jedem
Namen ("p.name") ab.
.LP
Aggregat-Operatoren k\o'o"'nnen ihre eigene Qualifikation haben.
Zum Beispiel k\o'o"'nnen wir eine Liste \o'u"'ber alle
Angestellten herstellen und das Durchschnittsgehalt f\o'u"'r
alle Angestellten \o'u"'ber 50 (Jahre) berechnen
und eintragen:
.DS L

* retrieve (p.name,pergeh=
* avg(p.gehalt where 1985-p.gebdat > 50))
* \eg

I N G - d b    . . .

|name                |pergeh    |
|-------------------------------|
|Schmidt, Petra      |  1277.444|
|Kayser, Helmut      |  1277.444|
|Loda, Dieter        |  1277.444|
|Thoms, Rolf         |  1277.444|
|Wunsch, Peter-Paul  |  1277.444|
|Mueller, Ernst      |  1277.444|
|Malter, Juergen     |  1277.444|
|Schneider, Peter    |  1277.444|
|Weise, Juergen      |  1277.444|
|Heine, Rolf         |  1277.444|
|Ernst, Eva          |  1277.444|
|Gruene, Peter       |  1277.444|
|Baum, Klaus         |  1277.444|
|Schmidt, Hermann    |  1277.444|
|Warnke, Peter       |  1277.444|
|Maerz, Udo          |  1277.444|
|Mueller, Petra      |  1277.444|
|Neumann, Inge       |  1277.444|
|Weber, Franz        |  1277.444|
|Zeidler, Fritz      |  1277.444|
|Moser, Otto         |  1277.444|
|Schulze, Ernst      |  1277.444|
|Fleischer, Karl     |  1277.444|
|Rose, Peter         |  1277.444|
|Rose, Petra         |  1277.444|
|-------------------------------|
25 tuples touched

ING_db:
*

.DE
Im Gegensatz zur vorhergehenden Query folgendes Beispiel.
Wir wollen die Namen derjenigen Angestellten \o'u"'ber f\o'u"'nfzig
suchen und das Durchschnittsgehalt f\o'u"'r alle berechnen.
.DS L

* retrieve (p.name,pergeh=avg(p.gehalt))
* where 1985-p.gebdat > 50
* \eg

I N G - d b   . . .

|name                |pergeh    |
|-------------------------------|
|Wunsch, Peter-Paul  |  1126.520|
|Malter, Juergen     |  1126.520|
|Schneider, Peter    |  1126.520|
|Heine, Rolf         |  1126.520|
|Ernst, Eva          |  1126.520|
|Gruene, Peter       |  1126.520|
|Zeidler, Fritz      |  1126.520|
|Rose, Peter         |  1126.520|
|Rose, Petra         |  1126.520|
|-------------------------------|
9 tuples touched

ING_db:
*

.DE
Es gibt einen bedeutenden Unterschied zwischen den beiden
letzten Queries.
Der Aggregat-Operator ist vollst\o'a"'ndig in sich abgeschlossen.
Er wird nicht durch die Qualifikation der
Query als Ganzes beeinflusst.
.LP
Im ersten Fall wurde der Durchschnitt nur f\o'u"'r
die Angestellten \o'u"'ber f\o'u"'nfzig berechnet und
\o'u"'ber alle Angestellten durchsucht.
Im zweiten Fall jedoch, wurde der Durchschnitt f\o'u"'r alle 
Angestellten berechnet, aber nur f\o'u"'r die Angestellten
\o'u"'ber f\o'u"'nfzig eingetragen.
.LP
Wenn wir eine Liste aller Angestellten \o'u"'ber 50 zusammen
mit dem durchschnittlichen Gehalt w\o'u"'nschen,
kombinieren wir die vorhergehenden zwei Queries zu einer.
Diese Query k\o'o"'nnte sein:

.DS L
* retrieve (p.name, pergeh=
* avg(p.gehalt where 1985 - p.gebdat > 50))
* where 1985 - p.gebdat > 50
* \eg

I N G - d b . . .

|name                |pergeh    |
|-------------------------------|
|Wunsch, Peter-Paul  |  1277.444|
|Malter, Juergen     |  1277.444|
|Schneider, Peter    |  1277.444|
|Heine, Rolf         |  1277.444|
|Ernst, Eva          |  1277.444|
|Gruene, Peter       |  1277.444|
|Zeidler, Fritz      |  1277.444|
|Rose, Peter         |  1277.444|
|Rose, Petra         |  1277.444|
|-------------------------------|
9 tuples touched

ING_db:
* 

.DE
Es ist manchmal gebr\o'a"'uchlich, dass doppelte Werte gel\o'o"'scht
werden, bevor ein Aggregat-Operator ausgef\o'u"'hrt wird.
Wenn sie beispielsweise wissen m\o'o"'chten, wieviele Leiter
("leiter") es gibt, wird die
folgende Query die richtige Antwort geben:

.DS L
* retrieve (chefs = count(p.leiter))
* \eg

I N G - d b . . .


|chefs        |
|-------------|
|           25|
|-------------|
1 tuples touched

ING_db:
* 

.DE
Beachten sie, dass "count" mitteilt, wieviele Tupel es in
"personal" gibt.
Was wir wissen wollten, war, 
wieviele Leiter ("p.leiter") es gibt.
.LP
\*(yy\ 6.3 stellt drei spezielle Formen von
Aggregat-Operatoren zur Verf\o'u"'gung.

.DS L
	countu		z\o'a"'hlt unikate (einmalig vorkommende)
                        Werte
	avgu		Durchschnitt \o'u"'ber unikate Werte
	sumu		summiert unikate Werte
.DE
.LP
Interessanterweise werden "minu", "maxu" und "anyu" nicht
ben\o'o"'tigt.
Ihre Werte sind die gleichen, unabh\o'a"'ngig davon, ob
doppelte Tupel vorkommen oder nicht.
.LP
Die korrekte Query, um die Anzahl der "leiter" zu finden, ist:

.DS L
* retrieve (chefs=countu(p.leiter))
* \eg

I N G - d b . . .


|chefs        |
|-------------|
|            9|
|-------------|
1 tuples touched

ING_db:
*

.DE
Eine andere Erleichterung, die \*(yy\ 6.3 unterst\o'u"'tzt, sind die
sogenannten Aggregat-Funktionen.
Aggregat-Funktionen gruppieren Daten
in Kategorien und unterst\o'u"'tzen separate Zusammenfassungen
zu jeder Kategorie.
.LP
Was ist zum Beispiel, wenn
wir f\o'u"'r die Angestellten, die zum selben
Leiter geh\o'o"'ren, das Durchschnittsgehalt ermitteln wollen?
Die Query w\o'u"'rde sein:
.DS L

* retrieve (p.name,leiteravg=avg(p.gehalt by p.leiter))
* \eg

I N G - d b   . . .

|name                |leiteravg |
|-------------------------------|
|Mueller, Ernst      |   700.000|
|Gruene, Peter       |  1453.000|
|Rose, Petra         |  1453.000|
|Loda, Dieter        |   668.500|
|Baum, Klaus         |   668.500|
|Kayser, Helmut      |   968.500|
|Weber, Franz        |   968.500|
|Fleischer, Karl     |   877.000|
|Maerz, Udo          |  1239.000|
|Mueller, Petra      |  1239.000|
|Schmidt, Hermann    |  1035.333|
|Warnke, Peter       |  1035.333|
|Neumann, Inge       |  1035.333|
|Schmidt, Petra      |  1111.667|
|Thoms, Rolf         |  1111.667|
|Wunsch, Peter-Paul  |  1111.667|
|Malter, Juergen     |  1111.667|
|Schneider, Peter    |  1111.667|
|Weise, Juergen      |  1111.667|
|Heine, Rolf         |  1111.667|
|Ernst, Eva          |  1111.667|
|Rose, Peter         |  1111.667|
|Zeidler, Fritz      |  1605.667|
|Moser, Otto         |  1605.667|
|Schulze, Ernst      |  1605.667|
|-------------------------------|
25 tuples touched

ING_db:
*

.DE
Die erste Person ist allein und
ihr Einkommen betr\o'a"'gt 700.00 M.
Die n\o'a"'chsten zwei Personen haben den selben Leiter und
das Durchschnittseinkommen betr\o'a"'gt 1453.00 usw.
.LP
Noch einmal, wenn wir die gleiche Liste eben
f\o'u"'r jene Angestellten \o'u"'ber 50 sehen m\o'o"'chten:
.DS L

* retrieve (p.name,leiteravg=avg(p.gehalt by p.leiter))
* where 1985-p.gebdat > 50
* \eg

I N G - d b   . . .

|name                |leiteravg |
|-------------------------------|
|Gruene, Peter       |  1453.000|
|Rose Petra          |  1453.000|
|Wunsch, Peter-Paul  |  1111.667|
|Malter, Juergen     |  1111.667|
|Schneider, Peter    |  1111.667|
|Heine, Rolf         |  1111.667|
|Ernst, Eva          |  1111.667|
|Rose, Peter         |  1111.667|
|Zeidler, Fritz      |  1605.667|
|-------------------------------|
9 tuples touched

ING_db:
*

.DE
Aggregat-Funktionen (im Gegensatz zu Aggregat-Operatoren) sind
nicht vollst\o'a"'ndig in sich abgeschlossen.
Die Dom\o'a"'nen, auf die die Daten gruppiert sind
(, durch die sogenannte "by_list"), sind logisch
mit den restlichen Dom\o'a"'nen der Query
verkn\o'u"'pft.
.LP
In diesem letzten Beispiel referenziert "p.leiter" in
der "by_list" zu den selben Tupeln wie
"p.name" in der "target_list".
.LP
Wenn wir das Durchschnittsgehalt nach Leitern nur f\o'u"'r
die Leiter 33 und 199 berechnen wollen,
erg\o'a"'be sich diese Query:
.DS L

* retrieve (p.name,leiteravg=
* avg(p.gehalt by p.leiter))
* where p.leiter = 199 or p.leiter = 33
* \eg

I N G - d b   . . .

|name                |leiteravg |
|-------------------------------|
|Kayser, Helmut      |   968.500|
|Weber, Franz        |   968.500|
|Schmidt, Petra      |  1111.667|
|Thoms, Rolf         |  1111.667|
|Wunsch, Peter-Paul  |  1111.667|
|Malter, Juergen     |  1111.667|
|Schneider, Peter    |  1111.667|
|Weise, Juergen      |  1111.667|
|Heine, Rolf         |  1111.667|
|Ernst, Eva          |  1111.667|
|Rose, Peter         |  1111.667|
|-------------------------------|
11 tuples touched


ING_db:
*

.DE
Nehmen wir an, wir wollen herausfinden,
wie viele Personen bei jedem Leiter
arbeiten und weiterhin wollen wir nur
die Personen einbeziehen, die
bereits vor 1970 dort arbeiteten.
.DS L

* retrieve (p.leiter,mitarb=count(p.name by p.leiter where
* p.einstdat < 1970))
* \eg

I N G - d b   . . .


|leiter|mitarb       |
|--------------------|
|     0|            2|
|    10|            0|
|    13|            0|
|    26|            2|
|    32|            0|
|    33|            2|
|    55|            1|
|   129|            2|
|   199|            8|
|--------------------|
9 tuples touched

ING_db:
*

.DE
Beachten sie, dass die Leiter 32, 10 und 13 keine
Angestellten haben, die vor 1970
dort angefangen haben.
Jetzt nehmen wir an, dass wir das Durchschnittsgehalt
f\o'u"'r diese Angestellten wissen wollen.
\o'A"'ndern sie einfach "count" in "avg" und starten sie die Query.
.DS L
* retrieve (p.leiter,mitarb=avg(p.gehalt by p.leiter where
* p.einstdat < 1970))
* \eg

I N G - d b   . . .

|leiter|mitarb    |
|-----------------|
|     0|  1453.000|
|    10|     0.000|
|    13|     0.000|
|    26|   954.000|
|    32|     0.000|
|    33|  1337.000|
|    55|  1362.000|
|   129|  1626.500|
|   199|  1088.125|
|-----------------|
9 tuples touched

ING_db:
*

.DE
Beachten sie, was \*(yy\ 6.3 f\o'u"'r die
Leiter 32, 10 und 13 macht.
Das Durchschnitsgehalt f\o'u"'r diese Angestellten 
ist tats\o'a"'chlich nicht
definiert, weil es keine Angestellten gibt, die vor 1970
angefangen haben.
\*(yy\ 6.3 wandelt undefinierte Werte immer
in Null.
.LP
Wenn sie die Nullwerte von der Ausgabe entfernen wollen,
kann das durch Hinzuf\o'u"'gung einer Qualifikation
zur Query erfolgen.
Die folgende Query wird nur die Durchschnittsgeh\o'a"'lter
finden, die einen Wert gr\o'o"'sser Null haben.
.DS L

* retrieve (p.leiter,mitarb=avg(p.gehalt by p.leiter where
* p.einstdat < 1970))
* where avg(p.gehalt by p.leiter where p.einstdat < 1970) > 0
* \eg

I N G - d b   . . .

|leiter|mitarb    |
|-----------------|
|     0|  1453.000|
|    26|   954.000|
|    33|  1337.000|
|    55|  1362.000|
|   129|  1626.500|
|   199|  1088.125|
|-----------------|
6 tuples touched

ING_db:
* 

.DE
Bis jetzt haben wir die Rechercheergebnisse direkt auf dem Terminal
ausgegeben.
Sie k\o'o"'nnen die Ergebnisse auch in eine neue Relation
retten bzw. sichern.
Das wird realisiert, wenn sie sagen:
.DS L

	retrieve into steigerung ( ... )
	where . . .

.DE
Die Regeln sind genau die gleichen, als w\o'u"'rden sie \o'u"'ber
das Terminal recherchieren.
\*(yy\ 6.3 gr\o'u"'ndet die neue Relation mit den
korrekten Dom\o'a"'nen und gibt die Ergebnisse
der Query in diese Relation.
.LP
Als Beispiel gr\o'u"'nden
wir eine neue Relation "steigerung", die nur die Angestellten
enth\o'a"'lt, die mehr als 1000 M verdienen:
.DS L

* retrieve into steigerung (p.all)
* where p.gehalt > 1000
* print steigerung
* \eg

I N G - d b   . . .

Relation: steigerung
K 1630 \*(yy\ EVK Olbernhau - K1630

|num   |name                |gehalt|leiter|gebdat|einstd|
|-------------------------------------------------------|
|    10|Rose, Peter         |  1590|   199|  1927|  1953|
|    11|Rose, Petra         |  1206|     0|  1931|  1951|
|    26|Schneider, Peter    |  1300|   199|  1930|  1970|
|    33|Ernst, Eva          |  1010|   199|  1931|  1963|
|    37|Neumann, Inge       |  1198|    26|  1950|  1974|
|    55|Malter, Juergen     |  1200|   199|  1920|  1969|
|   157|Schmidt, Petra      |  1200|   199|  1940|  1960|
|   199|Gruene, Peter       |  1700|     0|  1920|  1952|
|   430|Moser, Otto         |  1567|   129|  1938|  1959|
|   843|Schmidt, Hermann    |  1120|    26|  1936|  1956|
|   994|Schulze, Ernst      |  1564|   129|  1944|  1970|
|  1523|Zeidler, Fritz      |  1686|   129|  1928|  1949|
|  1639|Maerz, Udo          |  1116|    55|  1947|  1970|
|  5119|Mueller, Petra      |  1362|    55|  1939|  1963|
|  5219|Weber, Franz        |  1337|    33|  1944|  1959|
|-------------------------------------------------------|
15 tuples touched

ING_db:
*

.DE
Durch ein "retrieve into" wird nichts gedruckt bzw. ausgegeben.
Wir haben ein "print"-Kommando eingef\o'u"'gt, um
die Ergebnisse zu sehen.
Die Relation, die durch ein "retrieve into" benannt wird,
darf vorher nicht existieren.
Wenn wir beispielsweise versuchen,
die selbe Query zu wiederholen:
.DS L

* \eg

I N G - d b . . .

2135: line 1, You cannot duplicate the name of an
existing relation(steigerung)

ING_db:
*

.DE
.LP
Es gibt zwei spezielle Merkmale zu "retrieve into".
Erstens wird die Relation automatisch sortiert
und doppelte Tupel gel\o'o"'scht.
Zweitens wird die Relation Bestandteil der Datenbank
und sie werden ihr Eigent\o'u"'mer.
Wenn sie nicht wollen, dass sie erhalten bleibt, denken sie daran,
dass sie gel\o'o"'scht werden muss.
Der Ablauf zum L\o'o"'schen einer Relation wird
etwas sp\o'a"'ter erl\o'a"'utert.
.LP
Bisher haben wir nur Daten gesucht, aber niemals
welche ge\o'a"'ndert.
\*(yy\ 6.3 unterst\o'u"'tzt drei Aktualisierungskommandos:
"append", "replace" und "delete".
.LP
Beispielsweise wollen wir "Heinz Heinrich" zur 
Liste der Angestellten auf "steigerung" hinzuf\o'u"'gen und ihm
ein Gehalt von 1000 M zuordnen:
.DS L

* append to steigerung(name = "Heinrich, Heinz",gehalt = 1000)
* \eg

I N G - d b . . .

1 tuples touched

ING_db:
*

.DE
Beachten sie, dass wir nur zwei Werte spezifizierten,
obwohl "steigerung" aus sechs Dom\o'a"'nen besteht.
Das ist sch\o'o"'n!
\*(yy\ 6.3 setzt automatisch numerische Dom\o'a"'nen
auf Null und Zeichenkettendom\o'a"'nen auf "blank",
wenn sie nicht spezifiziert wurden.
.LP
Beachten sie auch, dass \*(yy\ 6.3 nach der Query nichts
ausgibt.
Das trifft f\o'u"'r alle Aktualisierungskommandos zu.
.LP
Wir wollen jedem in "steigerung" 10% Gehaltszuschlag geben.
Um das zu tun, ersetzen wir "gehalt" durch das Produkt aus
1,1 mal Wert.
Geben sie die Query ein:
.DS L

* range of s is steigerung
* replace s(gehalt = s.gehalt * 1.1)
* \eg

I N G - d b   . . .

16 tuples touched

ING_db:
*

.DE
W\o'a"'hrend das "append"-Kommando erwartet, dass sie einen
Relationen-Name (d.h. "append to steigerung") angeben, erwartet das
"replace"- und "delete"-Kommando eine 
Tupel-Variable.
Bemerken sie, dass das Kommando lautet:
.DS L

        replace s ( . . . )
                where . . .

und nicht:

        replace steigerung ( . . . )
                where . . .

.DE
Geben sie die Ergebnisse der beiden
letzten Aktualisierungen aus:
.DS L

* print steigerung
* \eg

I N G - d b   . . .


Relation: steigerung


|num   |name                |gehalt|leiter|gebdat|einstd|
|-------------------------------------------------------|
|    10|Rose, Peter         |  1749|   199|  1927|  1953|
|    11|Rose, Petra         |  1326|     0|  1931|  1951|
|    26|Schneider, Peter    |  1430|   199|  1930|  1970|
|    33|Ernst, Eva          |  1111|   199|  1931|  1963|
|    37|Neumann, Inge       |  1317|    26|  1950|  1974|
|    55|Malter, Juergen     |  1320|   199|  1920|  1969|
|   157|Schmidt, Petra      |  1320|   199|  1940|  1960|
|   199|Gruene, Peter       |  1870|     0|  1920|  1952|
|   430|Moser, Otto         |  1723|   129|  1938|  1959|
|   843|Schmidt, Hermann    |  1232|    26|  1936|  1956|
|   994|Schulze, Ernst      |  1720|   129|  1944|  1970|
|  1523|Zeidler, Fritz      |  1854|   129|  1928|  1949|
|  1639|Maerz, Udo          |  1227|    55|  1947|  1970|
|  5119|Mueller, Petra      |  1498|    55|  1939|  1963|
|  5219|Weber, Franz        |  1470|    33|  1944|  1959|
|     0|Heinrich, Heinz     |  1100|     0|     0|     0|
|-------------------------------------------------------|


ING_db:
*

.DE
Nun wollen wir denjenigen, der am wenigsten verdient, entlassen:
.DS L

* delete s where s.gehalt = min(s.gehalt) \eg
I N G - d b   . . .

1 tuples touched

ING_db:
*

.DE
Beachten sie, dass das "delete"-Kommando eine
Tupel-Variable (d.h. "delete s") erwartet
und keinen Relationen-Name.
.LP
Was ist, wenn wir wissen wollen, wer mehr als
Otto Moser verdient? Mit Heinz Heinrich k\o'o"'nnen wir nicht
mehr arbeiten, den haben wir entlassen.
Die Query, die das erledigt, ist recht schwierig.
Zuerst ben\o'o"'tigen wir eine neue Tupel-Variable, genannt
"o", die auf auf dem Bereich "steigerung" liegt
und benutzt wird, um Otto zu referenzieren.
"o.name" muss auf "Moser, Otto" gesetzt werden.
Danach m\o'u"'ssen wir eine Tupel-Variable "s"
nutzen, die die gesamte Relation durchforscht.
Jedesmal, wenn wir "s.gehalt > o.gehalt"
finden, dann verdient "s.name" mehr als Otto.
.LP
Die vollst\o'a"'ndige Query ist:
.DS L

* range of o is steigerung
* retrieve (s.name, sgeh=s.gehalt,ottogeh=o.gehalt)
* where s.gehalt > o.gehalt
* and o.name = "Moser, Otto"
* \eg

I N G - d b   . . .

|name                |sgeh  |ottoge|
|----------------------------------|
|Rose, Peter         |  1749|  1723|
|Gruene, Peter       |  1870|  1723|
|Zeidler, Fritz      |  1854|  1723|
|----------------------------------|
3 tuples touched

ING_db:
* 

.DE
Wenn wir Otto Moser 50 M mehr geben wollen, als
irgendeinem anderen, dann muss die Query lauten:
.DS L

* replace s(gehalt = max(s.gehalt) + 50)
* where s.name = "Moser, Otto"
* \eg
 
I N G - d b   . . .


ING_db:
* 

.DE
Schliesslich wollen wir noch eine Relation,
f\o'u"'r die sie Eigent\o'u"'mer sind,
l\o'o"'schen-geben sie das Kommando:
.DS L

* destroy steigerung
* \eg

I N G - d b   . . .

ING_db:
*

.DE
Wir sind jetzt fertig und verlassen \*(yy\ 6.3.
Das kann durch Eingabe eines
"end-of-file" (CONTROL_c)
oder g\o'u"'nstiger durch Verwendung des "\\q"-
Kommandos erreicht werden:
.DS L

* \eq
* ING-db Version 6.3/3 logout
K1630 / EVK Olbernhau - K1630
Wed May  4 19:58:00 1988
Auf Wiedersehen ing_db -- Kommen Sie bald wieder
.DE
.LP
Als "ing_db" wird immer der Nutzername eingetragen, ggfs.
aber eben auch ing_db.


