Base

Kapitel 5
Abfragen

Dokumentationen zu LibreOffice unter de.libreoffice.org

Copyright
Dieses Dokument unterliegt dem Copyright © 2014. Die Beitragenden sind unten aufgeführt. Sie
dürfen dieses Dokument unter den Bedingungen der GNU General Public License (http://www.gnu.org/licenses/gpl.html), Version 3 oder höher, oder der Creative Commons Attribution License(http://creativecommons.org/licenses/by/3.0/), Version 3.0 oder höher, verändern und/oder weitergeben.
Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt.
Fast alle Hardware- und Softwarebezeichnungen und weitere Stichworte und sonstige Angaben,
die in diesem Buch verwendet werden, sind als eingetragene Marken geschützt.
Da es nicht möglich ist, in allen Fällen zeitnah zu ermitteln, ob ein Markenschutz besteht, wird das
Symbol (R) in diesem Buch nicht verwendet.

Mitwirkende/Autoren
Robert Großkopf

Jost Lange

Jochen Schiffers

Michael Niedermair

Rückmeldung (Feedback)Kommentare oder Vorschläge zu diesem Dokument können Sie in deutscher Sprache an die
Adresse discuss@de.libreoffice.org senden.

Vorsicht

Alles, was an eine Mailingliste geschickt wird, inklusive der E-Mail-Adresse undanderer persönlicher Daten, die die E-Mail enthält, wird öffentlich archiviert und kannnicht gelöscht werden. Also, schreiben Sie mit Bedacht!

Datum der Veröffentlichung und Softwareversion
Veröffentlicht am 15.8.2014. Basierend auf der LibreOffice Version 4.3.

Anmerkung für Macintosh Nutzer
Einige Tastenbelegungen (Tastenkürzel) und Menüeinträge unterscheiden sich zwischen derMacintosh Version und denen für Windows- und Linux-Rechnern. Die unten stehende Tabelle gibt
Ihnen einige grundlegende Hinweise dazu. Eine ausführlichere Aufstellung dazu finden Sie in der
Hilfedatei des jeweiligen Moduls.
Windows/Linux

entspricht am Mac

EffektMenü-Auswahl Extras →Optionen

LibreOffice → EinstellungenZugriff auf die Programmoptionen

Rechts-Klick

Control+Klick
ControlÖffnen eines Kontextmenüs

Ctrl (Control)oder Strg (Steuerung)⌘ (Command)

Tastenkürzel in Verbindung mit anderen
TastenF5Shift+⌘
F5
Shift ⌘+F5

Öffnen des Dokumentnavigator-Dialogs

F11

⌘+T
T

Öffnen des Formatvorlagen-Dialogs

Abfragen2

Inhalt
Allgemeines zu Abfragen ................................................................................................................ 4
Eingabemöglichkeiten für Abfragen ................................................................................................ 4
Abfrageerstellung mit der grafischen Benutzeroberfläche .......................................................... 4
Funktionen in der Abfrage ................................................................................................... 12
Beziehungsdefinition in der Abfrage .................................................................................... 15
Abfrageeigenschaften definieren ......................................................................................... 19
Abfrageerweiterungen im SQL-Modus ..................................................................................... 21
Verwendung eines Alias in Abfragen ............................................................................................ 30
Abfragen für die Erstellung von Listenfeldern ............................................................................... 31
Abfragen als Grundlage von Zusatzinformationen in Formularen ................................................. 33
Eingabemöglichkeit in Abfragen ................................................................................................... 34
Verwendung von Parametern in Abfragen .................................................................................... 38
Unterabfragen .............................................................................................................................. 39
Korrelierte Unterabfrage ............................................................................................................... 40
Abfragen als Bezugstabellen von Abfragen .................................................................................. 40
Zusammenfassung von Daten mit Abfragen ................................................................................. 44
Schnellerer Zugriff auf Abfragen durch Tabellenansichten ............................................................ 45

3

Allgemeines zu Abfragen
Abfragen an eine Datenbank sind das mächtigste Werkzeug, was uns zur Verfügung steht, um
Datenbanken sinnvoll zu nutzen. Sie fassen Daten aus unterschiedlichen Tabellen zusammen,
berechnen gegebenenfalls irgendwelche Ergebnisse, filtern einen ganz bestimmten Datensatz aus
einer Unmenge an Daten mit hoher Geschwindigkeit heraus. Die großen Internetdatenbanken, dieviele täglich nutzen, haben ihren Hauptsinn darin, dass aus der Unmenge an Informationen durch
geschickte Wahl der Schlüsselwörter schnell ein brauchbares Ergebnis für den Nutzer geliefert
wird – einschließlich natürlich der zu den Suchbegriffen gehörenden Anzeigen, die zum Kauf animieren sollen.

Eingabemöglichkeiten für Abfragen
Die Eingabe von Abfragen kann sowohl in der GUI als auch direkt per SQL erfolgen. In beiden Fällen öffnet sich ein Fenster, das es ermöglicht, die Abfragen auszuführen und gegebenenfalls zu
korrigieren.

Abfrageerstellung mit der grafischen Benutzeroberfläche
Die Erstellung von Abfragen mit dem Assistenten wird in dem «Erste Schritte Handbuch» «Einführung in Base» kurz dargestellt. Hier wird stattdessen die direkte Erstellung über Abfrage in der
Entwurfsansicht erstellen erklärt.
Nach einem Aufruf der Funktion erscheinen zwei Fenster. Ein Fenster stellt die Grundlagen für den
Design-Entwurf der Abfrage zur Verfügung, das andere dient dazu, Tabellen, Ansichten oder Abfragen der Abfrage hinzuzufügen.
Da unser einfaches Formular auf der Tabelle "Ausleihe" beruhte, wird zuerst einmal an dieser
Tabelle die Grundkonstruktion von Abfragen mit dem Abfrageeditor erklärt.

Eingabemöglichkeiten für Abfragen4

Grafischer Bereich(zur Darstellung von Tabellen undBeziehungen der Tabellen untereinander)

Tabellarischer Bereich
●
●
●
●
●
●

Auswahl der anzuzeigenden Felder der oben angezeigten Tabellen
Anzuzeigender Name der Felder (mit Alias)
Sortierung nach dem ausgewählten Feld
Unsichtbarschaltung eines Feldes
Funktionen abhängig von der verwandten Datenbank
Kriterienformulierung zur Filterung der Daten

Abbildung 1: Bereiche des Abfrageentwurfs
Aus den zur Verfügung stehenden Tabellen wird die Tabelle Ausleihe ausgewählt. Dieses Fenster
bietet die Möglichkeit, gleich mehrere Tabellen (und unter diesen auch Ansichten) sowie Abfragenmiteinander zu kombinieren. Jede gewünschte Tabelle wird markiert (linke Maustaste) und danndem grafischen Bereich des Abfrageeditors hinzugefügt.
Sind alle erforderlichen Tabellen ausgewählt, so wird dieses Fenster geschlossen. Gegebenenfalls
können später noch mehr Tabellen und Abfragen hinzugefügt werden. Ohne eine einzige Tabelle
lässt sich aber keine Abfrage erstellen, so dass eine Auswahl zu Beginn schon sein muss.
Abbildung 1 zeigt die grundsätzliche Aufteilung des grafischen Abfrageeditors: Im grafischen
Bereich werden die Tabellen angezeigt, die mit der Abfrage zusammen hängen sollen. Hier kannauch ihre Beziehung zueinander in Bezug auf die Abfrage angegeben werden. Im tabellarischen
Bereich erfolgt die Auswahl der Felder, die angezeigt werden sollen sowie Bedingungen, die mit
diesen Feldern verbunden sind.
Ein Klick mit der Maustaste auf das Feld der ersten Spalte im tabellarischen Bereich öffnet die
Feldauswahl:

Eingabemöglichkeiten für Abfragen5

Hier stehen jetzt alle Felder der Tabelle "Ausleihe" zur Verfügung. Die Schreibweise: Tabellenname.Feldname – deshalb beginnen alle Feldbezeichnungen hier mit dem Begriff "Ausleihe.".
Eine besondere Bedeutung hat die markierte Feldbezeichnung Ausleihe.* . Hier wird mit einem
Klick jeder Feldname der zugrundeliegenden Tabelle in der Abfrage wiedergegeben. Wenn allein
diese Feldbezeichnung mit dem Jokerzeichen «*» für alle Felder gewählt wird unterscheidet sich
die Abfrage nicht von der Tabelle.

Tipp

Sollen schnell alle möglichen Felder aus Tabellen in die Abfrage übertragen werden,
so kann auch direkt im grafischen Bereich auf die Tabellenübersicht geklickt werden.
Mit einem Doppelklick auf ein Feld wird das Feld im tabellarischen Bereich an dernächsten freien Position eingefügt.

Eingabemöglichkeiten für Abfragen6

Es werden die ersten fünf Felder der Tabelle Ausleihe ausgewählt. Abfragen können auch im Design-Modus immer wieder testweise ausgeführt werden. Dann erscheint oberhalb der grafischen
Ansicht der Tabelle eine tabellarische Übersicht über die Daten. Die testweise Ausführung vonAbfragen ist vor dem Abspeichern immer sinnvoll, damit für den Nutzer klar ist, ob die Abfrageauch wirklich das erreicht, was sie erreichen soll. Manchmal wird durch einen Denkfehler ausgeschlossen, dass eine Abfrage überhaupt je Daten ausgeben kann. Ein anderes Mal kann es passieren, dass plötzlich genau die Datensätze angezeigt werden, die ausgeschlossen werden sollten.

Eingabemöglichkeiten für Abfragen7

Grundsätzlich lässt sich eine Abfrage, die eine Fehlerrückmeldung bei der zugrundeliegenden
Datenbank produziert, gar nicht erst abspeichern.

Abbildung 2: Abfrage
bearbeitbar

Abbildung 3: Abfragenicht bearbeitbar

Besonderes Augenmerk sollte in dem obigen Test einmal auf die erste Spalte des dargestellten
Abfrageergebnisses geworfen werden. Auf der linken Seite der Tabelle erscheint immer der Datensatzmarkierer, der hier auf den ersten Datensatz als aktivem Datensatz hinweist. Während in
Abbildung 2 aber das erste Feld des ersten Datensatzes grün markiert ist zeigt das erste Feld in
Abbildung 3 nur eine gestrichelte Umrandung an. Die grüne Markierung deutet bereits an, dasshier im Feld selbst etwas geändert werden kann. Die Datensätze sind also änderbar. In
Abbildung 2 ist außerdem eine zusätzliche Zeile zur Eingabe neuer Daten vorhanden, in der für
das Feld "ID" schon <AutoWert> vorgemerkt ist. Auch hier also sichtbar, dass Neueingaben möglich sind.
Grundsätzlich sind dann keine Neueingaben möglich, wenn der Primärschlüssel der abgefragten
Tabelle nicht in der Abfrage enthalten ist.

Den Feldern "Leih_Datum" und "Rueck_Datum" wurde ein Aliasname zugewiesen. Sie wurden
damit nicht umbenannt, sondern unter diesem Namen für den Nutzer der Abfrage sichtbar
gemacht.

Entsprechend ist in der Tabellenansicht der Alias statt der eigentlichen Feldbezeichnung zu sehen.

Dem Feld "Rueck_Datum" wurde nicht nur ein Alias sondern auch ein Kriterium zugewiesen, nachdem nur die Datensätze angezeigt werden sollen, bei denen das Feld "Rueck_Datum" leer ist. Die
Eingabemöglichkeiten für Abfragen

8Angabe erfolgt hier in deutscher Sprache, wird dann aber in der eigentlichen Abfrage in SQL übersetzt.
Durch dieses Ausschlusskriterium werden nur die Datensätze von Medien angezeigt, die ein
Medium enthalten, das noch nicht zurückgegeben wurde.

Um die SQL-Sprache besser kennen zu lernen empfiehlt es sich immer wieder einmal vom Design-Modus aus in den SQL-Darstellungsmodus zu wechseln.

Hier wurde die durch die Auswahlen erstellte SQL-Formulierung sichtbar gemacht. Für die bessereÜbersicht ist die Ansicht mit Zeilenumbrüchen versehen worden. Leider speichert der Editor dieseZeilenumbrüche nicht mit ab, so dass beim nächsten Aufruf die Abfrage wieder komplett als eine
durchgängige Zeile mit Umbruch am Fensterrand wiedergegeben wird.
Über SELECT wird die Auswahl gestartet. Mit AS werden die Aliasbezeichnungen eingeführt.
FROM zeigt auf die Tabellenquelle der Abfrage. WHERE gibt die Bedingung für die Abfrage wieder,hier also, dass der Inhalt des Feldes "Rueck_Datum" leer ist (IS NULL). Mit ORDER BY wird die
Sortierung definiert, und zwar als aufsteigend (ASC – ascending) für die beiden Felder "Leser_ID"
und "Ausleihdatum". Diese Sortierung zeigt auch, dass die Zuweisung eines Alias das Feld
"Leih_Datum" auch in der Abfrage selbst mit dem Alias ansprechbar macht.
Bisher sind die Felder "Medien_ID" und "Leser_ID" nur als Zahlenfelder sichtbar. Welchen Namen
der Leser hat bleibt unklar. Um dies in einer Abfrage anzuzeigen muss die Tabelle Leser eingebunden werden. Um die folgende Ansicht zu erhalten muss in den Design-Modus zurückgeschaltet
werden. Danach kann dann eine neue Tabelle in der Design-Ansicht hinzugefügt werden.

Eingabemöglichkeiten für Abfragen

9

Hier können im Nachhinein weitere Tabellen oder Abfragen in der grafischen Benutzeroberfläche
sichtbar gemacht werden. Sind bei der Erstellung der Tabellen Beziehungen geklärt worden ( siehe
Kapitel «Beziehungen zwischen Tabellen allgemein»), dann werden die Tabellen entsprechend
direkt miteinander verbunden angezeigt:

Fehlt die Verbindung, so kann hier durch ein Ziehen mit der Maus von "Ausleihe"."Leser_ID" zu"Leser"."ID" eine direkte Verknüpfung erstellt werden.

HinweisEine Verbindung von Tabellen geht zur Zeit nur, wenn es sich um die interne Datenbank oder ein relationales Datenbanksystem handelt. Tabellen einer Tabellenkalkulation z. B. lassen sich so nicht miteinander verbinden. Sie müssen dazu in eineinterne Datenbank importiert werden.
Um die Verbindung der Tabellen herzustellen reicht ein Import ohne zusätzliche
Erstellung eines Primärschlüssels aus.

Jetzt können im tabellarischen Bereich auch die Felder der Tabelle "Leser" ausgewählt werden.
Die Felder werden dabei erst einmal am Schluss der Abfrage angeordnet.

Mit der Maus kann in dem tabellarischen Bereich des Editors die Lage der Felder korrigiert werden. Hier wird z. B. gerade das Feld Vorname direkt vor das Feld "Leih_Datum" verlegt.

Eingabemöglichkeiten für Abfragen

10Die Namen wurden jetzt sichtbar gemacht. Die "Leser_ID" ist eigentlich überflüssig. Auch ist die
Sortierung nach "Nachname" und "Vorname" eigentlich sinnvoller als nach der "Leser_ID".
Diese Abfrage eignet sich nicht mehr für Base als Abfrage mit Eingabemöglichkeit, da zu der neu
hinzugekommenen Tabelle Leser der Primärschlüssel fehlt. Erst wenn auch dieser Primärschlüssel
eingebaut wird ist die Abfrage wieder editierbar – allerdings komplett editierbar, so dass auch die
Namen der Leser geändert werden können. Die Möglichkeit der Editierbarkeit ist also sehr vorsichtig zu nutzen, gegebenenfalls über ein Formular einzuschränken.
Selbst wenn die Abfrage weiter editierbar ist, lässt sie sich nicht so komfortabel nutzen wie ein Formular mit Listenfeldern, die zwar die Lesernamen anzeigen, aber die "Leser_ID" an die Tabelle
weitergeben. Listenfelder lassen sich in eine Abfrage nicht einfügen. Sie sind den Formularen vorbehalten.

Wird jetzt auf die SQL-Ansicht umgeschaltet so zeigt sich, dass alle Felder mit einer Doppelbezeichnung gekennzeichnet sind: "Tabellenname"."Feldname". Dies ist notwendig, damit derDatenbank klar wird, aus welcher Tabelle die jeweiligen Feldinhalte stammen. Schließlich können
Felder in unterschiedlichen Tabellen ohne weiteres den gleichen Feldnamen tragen. Bei den bisherigen Tabellenkonstruktionen trifft dies z. B. immer auf das Feld "ID" zu.
Folgende Abfrage funktioniert auch ohne Tabellenname vor den Feldnamen:
SELECT"Ware"."ID","Abgang"."Anzahl","Ware"."Preis"
FROM "Ware","Abgang"
WHERE "Abgang"."warID" = "Ware"."ID"

HinweisHierbei wird "ID" aus der Tabelle gezogen, die als erste in der FROM-Definition
steht. Auch die Tabellendefinition in der WHERE-Formulierung wäre überflüssig, da"warID" nur einmal in der Tabelle "Abgang" vorkommt und die ID aus der Tabelle"Ware" genommen wird (Position der Tabelle). Die folgende Abfrage liefert also das
gleiche Ergebnis:
SELECT"ID","Anzahl","Preis"FROM "Ware","Abgang"
WHERE "warID" = "ID"Wird einem Feld in der Abfrage ein Alias zugewiesen, so kann sie z. B. in der Sortierung mit diesem Alias ohne einen Tabellennamen angesprochen werden. Sortierungen werden in der grafischen Benutzeroberfläche nach der Reihenfolge der Felder in der Tabellenansicht vorgenommen.
Sollte stattdessen zuerst nach "Ausleihdatum" und dann nach "Ausleihe"."Leser_ID" sortiert werden, so kann dies erzeugt werden, indem

Eingabemöglichkeiten für Abfragen11• die Reihenfolge der Felder im tabellarischen Bereich der grafischen Benutzeroberfläche
geändert wird,• ein zweites Feld eingefügt wird, das auf unsichtbar geschaltet ist und nur die Sortierung
gewährleisten soll ( wird allerdings beim Editor nur vorübergehend angenommen, wennkein Alias definiert wurde) oder
• der Text für die 'ORDER BY' – Anweisung im SQL-Editor entsprechend umgestellt wird.
Die Beeinflussung der Sortierreihenfolge arbeitet je nach Version nicht ganz fehlerfrei. Wird in
LO 3.3.4 die Reihenfolge anders gewählt als durch die GUI vorgegeben, so funktioniert die
Abfrage korrekt. Ein erneutes Aufrufen der Abfrage zur Bearbeitung zeigt aber die Einstellung derSortierung nach Reihenfolge der Felder in der GUI. Die Kontrolle ergibt dann auch eine entsprechend geänderte Sortierreihenfolge wie angezeigt wieder. Sobald also die Abfrage nach einer
zusätzlichen Änderung an anderer Stelle gespeichert wird, ist die Sortierung leider unbeabsichtigt
mit geändert worden. In LO 3.5.3 RC2 wird die Sortierung aus der SQL-Ansicht korrekt übernommen und entsprechend mit nicht sichtbaren Feldern in der grafischen Benutzeroberfläche angezeigt.

Funktionen in der Abfrage
Mittels Funktionen lässt sich aus Abfragen auch mehr ersehen als nur ein gefilterter Blick auf die
Daten einer oder mehrerer Tabellen. In der folgenden Abfrage wird, abhängig von der "Leser_ID",
gezählt, wie viele Medien ausgeliehen wurden.

Für die "ID" der Tabelle "Ausleihe" wird die Funktion Anzahl ausgewählt. Prinzipiell ist hier egal,welches Feld einer Tabelle gewählt wurde. Die einzige Bedingung: Das Feld darf nicht in irgendwelchen Datensätzen leer sein. Aus diesem Grunde ist der Primärschlüssel, der ja nie leer ist,
immer eine geeignete Wahl. Gezählt werden die Felder, die einen Inhalt enthalten, der von NULL
verschieden ist.
Für die "Leser_ID", die ja Rückschlüsse auf den Leser zulässt, wird als Funktion die Gruppierung
gewählt. Dadurch werden die Datensätze nach der "Leser_ID" zusammengefasst. So zählt denn
die Anweisung die Datensätze, die zu jeder "Leser_ID" passen.
Als Kriterium ist wie in den vorhergehenden Beispielen das "Rueck_Datum" auf IST LEER gesetzt.

Eingabemöglichkeiten für Abfragen

12Die Abfrage zeigt im Ergebnis, dass z. B. "Leser_ID" '0' insgesamt noch 3 Medien entliehen hat.
Wäre die Funktion Anzahl statt der "ID" dem "Rueck_Datum" zugewiesen worden, so würden füralle "Leser_ID" jeweils '0' entliehene Medien dargestellt, da ja "Rueck_Datum" als LEER vordefiniert ist.
Die entsprechende Formulierung für den SQL-Code ist oben wieder abgebildet. Aus dem Begriff
Anzahl der deutschen GUI wird COUNT(). Aus dem Begriff Gruppierung wird der Zusatz GROUP
BY.
Insgesamt stehen über die grafische Benutzeroberfläche folgende Funktionen zur Verfügung, dieihre Entsprechung zu Funktionen in der zugrundeliegenden HSQLDB haben:

Eine Erläuterung zu den Funktionen ist in dem folgenden Kapitel Abfrageerweiterungen im SQLModus nachzulesen.
Wird einem Feld in einer Abfrage eine Funktion hinzugefügt, so müssen alle anderen Felder derAbfrage auch mit Funktionen versehen sein, sofern die Felder sichtbar sein sollen. Dies liegt
daran, dass in einem Datensatz nicht plötzlich zwischendurch Felder mehrere Datensätze abbilden
können. Wird dies nicht beachtet, so erscheint die folgende Fehlermeldung:

Eingabemöglichkeiten für Abfragen13

Etwas frei übersetzt: Der folgenden Ausdruck enthält keine der Sammelfunktionen oder eine Gruppierung.
Danach wird die gesamte Abfrage aufgelistet, leider ohne das Feld konkret zu benennen. Hier
wurde einfach das Feld "Rueck_Datum" als sichtbar hinzugefügt. Dieses Feld hat keine Funktion
zugewiesen bekommen und ist auch nicht in der Gruppierung enthalten.
Die über den Button 'Mehr' erreichbaren Informationen sind für den Normalnutzer einer Datenbank
nicht aufhellender. Hier wird lediglich zusätzlich noch der SQL-Fehlercode aufgeführt.
Innerhalb der GUI können auch die Grundrechenarten sowie weitere Funktionen angewandt werden.

Hier wurden die Tabelle "Ausleihe" und die Tabelle "Mahnung" zusammen abgefragt. Aus der Zahl
der Datumseinträge in der Tabelle "Mahnung" wird auf die Anzahl der Mahnungen geschlossen.
Als Mahnbetrag wird in der Abfrage 2,- € festgelegt. Statt der Feldauswahl wird in das Feld einfach
geschrieben: Anzahl(Mahnung.Datum)*2 . Die grafische Benutzeroberfläche setzt anschließend die Anführungsstriche und wandelt den Begriff Anzahl in den entsprechenden SQL-Begriffum.

Vorsicht

Werden in der grafischen Benutzeroberfläche Zahlen mit Nachkommastellen eingegeben, so ist auf jeden Fall darauf zu achten, dass statt eines Kommas ein Punkt
der Trenner für Dezimalzahlen in SQL ist. Kommata sind hingegen die Trenner derFelder. Ein Komma in der GUI-Eingabe bringt LO 3.3.4 direkt zum Totalabsturz.
Seit der Version 3.5.3 ist dies nicht mehr der Fall. Stattdessen werden neue Abfragefelder gegründet, die die Nachkommastellen ausgeben.
Eine Eingabe mit Komma in der SQL-Ansicht führt hingegen dazu, dass ein weiteres
Feld allein mit dem Zahlenwert der Nachkommastelle angezeigt wird. Dies entspricht
dem Verhalten der grafischen Benutzeroberfläche in LO 3.5.3.

Eingabemöglichkeiten für Abfragen

14

Die Abfrage ermittelt jetzt für jedes noch entliehene Medium anhand der herausgegebenen Mahnungen und der zusätzlich eingefügten Multiplikation die Mahngebühren. Die folgende Abfragekonstruktion hilft weiter, wenn die Gebühren für jeden Leser berechnet werden sollen:

Die Felder "Ausleihe"."ID" und "Ausleihe"."Medien_ID" wurden entfernt. Sie erzeugten in der vorherigen Abfrage über die Gruppierung für jedes Medium einen separaten Datensatz. Jetzt wird nur
noch nach den Lesern gruppiert. Das Abfrageergebnis sieht dann so aus:

Statt die Medien für "Leser_ID" '0' separat aufzulisten werden alle Felder aus "Mahnung"."Datum"
zusammengezählt und die Summe von 8,- € als Mahngebühr ermittelt.

Beziehungsdefinition in der Abfrage
Werden Daten in Tabellen oder einem Formular gesucht, so beschränkt sich die Suche in derRegel auf eine Tabelle bzw. auf ein Formular. Selbst der Weg von einem Hauptformular zu einem
Unterformular ist für die eingebauten Suchfunktionen nicht gangbar. Da bietet es sich dann an, zu
durchsuchende Daten mit einer Abfrage zusammenzufassen.

Eingabemöglichkeiten für Abfragen

15

Die einfache Abfrage an die "Titel" aus der Tabelle "Medien" zeigt den eingegebenen Testbestanddieser Tabelle mit 9 Datensätzen an. Wird jedoch die Tabelle "Untertitel" mit in die Abfrage aufgenommen, so reduziert sich der Datenbestand aus der Tabelle "Medien" auf lediglich 2 "Titel". Nurfür diese beiden "Titel" gibt es auch "Untertitel" in der Tabelle "Untertitel". Für alle anderen "Titel"
existieren keine "Untertitel". Dies entspricht der Verknüpfungsbedingung, dass nur die Datensätze
angezeigt werden sollen, bei denen in der Tabelle "Untertitel" das Feld "Medien_ID" gleich dem
Feld "ID" aus der Tabelle "Medien" ist. Alle anderen Datensätze werden ausgeschlossen.

Die Verknüpfungsbedingung muss zum Bearbeiten geöffnet werden, damit alle gewünschten
Datensätze angezeigt werden. Es handelt sich hier nicht um die Verknüpfung von Tabellen im
Relationenentwurf sondern um die Verknüpfung in einer Abfrage.

Eingabemöglichkeiten für Abfragen

16

Standardmäßig steht die Verknüpfung als Innerer Verbund zur Verfügung. Das Fenster gibt darüber Aufschluss, wie diese Form der Verknüpfung sich auswirkt.
Als beteiligte Tabellen werden die beiden vorher ausgewählten Tabellen gelistet. Sie sind hier nicht
wählbar. Die beteiligten Felder der beiden Tabellen werden aus der Tabellendefinition ausgelesen.
Ist eine Beziehung in der Tabellendefinition nicht vorgegeben, so kann sie hier für die Abfrage
erstellt werden. Eine saubere Datenbankplanung mit der HSQLDB sieht aber so aus, dass auch andiesen Feldern nichts zu verstellen ist.
Wichtigste Einstellung ist die Option des Verbundes. Hier können Verknüpfungen so gewählt werden, dass alle Datensätze von der Tabelle "Untertitel" und nur die Datensätze aus "Medien"
gewählt werden, die in der Tabelle "Untertitel" auch "Untertitel" verzeichnet haben.
Umgekehrt kann gewählt werden, dass auf jeden fall alle Datensätze aus der Tabelle "Medien"angezeigt werden – unabhängig davon, ob für sie auch "Untertitel existieren.
Die Option Natürlich setzt voraus, dass die zu verknüpfenden Felder in den Tabellen gleich lauten.
Auch von dieser Einstellung ist Abstand zu nehmen, wenn bereits zu Beginn bei der Datenbankplanung die Beziehungen definiert wurden.

Eingabemöglichkeiten für Abfragen

17

Für den Typ Rechter Verbund zeigt die Beschreibung an, dass aus der Tabelle "Medien" auf jeden
Fall alle Datensätze angezeigt werden. Da es keine "Untertitel" gibt, die nicht in "Medien" miteinem "Titel" verzeichnet sind, sehr wohl aber "Titel" in "Medien", die nicht mit einem "Untertitel"versehen sind, ist dies also die richtige Wahl.

Nach Bestätigung des rechten Verbundes sieht das Abfrageergebnis aus wie gewünscht. "Titel"und "Untertitel" werden komplett zusammen in einer Abfrage angezeigt. Natürlich kommen jetzt"Titel" wie in der vorhergehenden Verknüpfung mehrmals vor. Solange allerdings Suchtreffer nicht
gezählt werden könnte diese Abfrage im weiteren Verlauf als Grundlage für eine Suchfunktion dieEingabemöglichkeiten für Abfragen18

nen. Siehe hierzu die Codeschnipsel in diesem Kapitel, im Kapitel «Makros» («Suchen von Datensätzen»)und im Kapitel «DB-Aufgaben komplett» («Datensuche»).

Vorsicht

Werden mehrere Tabellen über einen rechten oder linken Verbund bearbeitet, so
verarbeitet die grafische Benutzeroberfläche unter LO 3.3.4 den Verbundbefehl nicht
korrekt. Dies führt dazu, dass die Abfrage mit einem SQL-Fehler abgebrochen wird.
Seit der Version 3.5.3 ist dies nicht mehr der Fall!
Die Eingabe im SQL-Modus ist hiervon nicht berührt.

Abfrageeigenschaften definieren
Mit der Version 4.1 von LibreOffice ist es möglich, in dem Abfrageeditor zusätzliche Abfrageeigenschaften zu definieren.

Abbildung 4: Aufruf der Abfrageeigenschaften im
Abfrageeditor (ab LO 4.1)
Neben dem Button zum Aufruf der Abfrageeigenschaften befindet sich noch ein Kombinationsfeld,
mit dem die Anzahl der anzuzeigenden Datensätze reguliert werden kann, sowie ein Button «Eindeutige Werte». Diese Funktionen sind zusätzlich noch einmal in dem folgenden Dialog untergebracht:

Mit der Einstellung «Eindeutige Werte» wird beeinflusst, ob gleichlautende Datensätze in den
Abfragen unterdrückt werden sollen.

Eingabemöglichkeiten für Abfragen19

In einer Abfrage soll ermittelt werden, welche Leser und Leserinnen noch Medien entliehen haben.
Die Namen werden angezeigt, wenn das Rückgabedatum leer ist. Allerdings werden die Namen
mehrmals angezeigt, wenn ein Leser oder eine Leserin noch mehrere Medien entliehen hat.

Wird «Eindeutige Werte» ausgewählt, so verschwinden die Datensätze mit gleichem Inhalt.
Die Abfrage sind dann so aus:

Der ursprünglichen Abfrage
SELECT "Leser"."Vorname", "Leser"."Nachname" …
wird ein «DISTINCT» hinzugefügt:
SELECT DISTINCT "Leser"."Vorname", "Leser"."Nachname" …
Damit werden alle gleichlautenden Zeilen unterdrückt.
Die Auswahl eindeutiger Werte war auch in den Vorversionen möglich. Allerdings musste hier von
der Design-Ansicht in die SQL-Ansicht umgeschaltet werden, um den Begriff «DISTINCT» einzufügen. Diese Eigenschaft ist also ohne Probleme abwärtskompatibel zu den Vorversionen von LO.
Mit der Einstellung «Limit» wird beeinflusst, wie viele Datensätze in der Abfrage angezeigt werdensollen. Es wird also nur eine begrenzte Zahl an Datensätzen wieder gegeben.

Alle Datensätze der Tabelle "Medien" werden angezeigt. Die Abfrage ist editierbar, da auch der Primärschlüssel enthalten ist.

Eingabemöglichkeiten für Abfragen

20

Nur die ersten fünf Datensätze werden angezeigt (ID 0 bis 4). Eine Sortierung wurde nicht vorgewählt. Die Standardsortierung ist hier die nach dem Primärschlüssel, sofern nichts anderes festgelegt wurde. Die Abfrage ist trotz der Begrenzung weiterhin editierbar. Dies unterscheidet die Eingabe im grafischen Modus von der, die in früheren Versionen nur mit dem direkten SQL-Modus
erreichbar ist.

Der ursprünglichen Abfrage wurde lediglich «LIMIT 5» hinzugefügt. Die entsprechende Größe desLimits kann beliebig festgelegt werden.

Vorsicht

Die Einstellung des Limits durch die grafische Benutzeroberfläche ist nicht abwärtskompatibel. In allen LO-Versionen vor der Version 4.1 konnte ein Limit nur im direkten SQL-Modus eingegeben werden. Dort erforderte das Limit eine Sortierung(ORDER BY …) oder eine Bedingung (WHERE …).

Abfrageerweiterungen im SQL-Modus
Wird von der grafischen Eingabe über Ansicht → Design-Ansicht an-, ausschalten die DesignAnsicht ausgeschaltet, so erscheint der SQL-Befehl, der bisher in der Design-Ansicht erstellt
wurde. Für Neueinsteiger ist dies der beste Weg, die Standardabfragesprache für Datenbanken
kennen zu lernen. Manchmal ist es auch der einzige Weg, eine Abfrage an die Datenbank abzusetzen, da die GUI die Abfrage nicht in den für die Datenbank notwendigen SQL-Befehl umwandeln
kann.
SELECT*
FROM "Tabellenname"Dies zeigt wirklich alles an, was in der Tabelle "Tabellenname" steht. Das «*» berücksichtigt sämtliche Felder der Tabelle.
SELECT*
FROM "Tabellenname"
WHERE "Feldname" = 'Karl'
Eine deutliche Einschränkung wurde gemacht. Jetzt werden nur noch die Datensätze angezeigt,
die in dem Feld "Feldname" den Begriff 'Karl' stehen haben – aber wirklich nur den Begriff, nichtz. B. 'Karl Egon'.
Manchmal sind Abfragen in Base nicht über die GUI ausführbar, da bestimmte Kommandos nicht
bekannt sind. Hier hilft es dann die Design-Ansicht zu verlassen und über Bearbeiten → SQLKommando direkt ausführen den direkten Weg zur Datenbank zu wählen. Diese Methode hatallerdings den Nachteil, dass in dem angezeigten Abfrageergebnis keine Eingaben mehr möglichsein. Siehe hierzu Eingabemöglichkeit in Abfragen.
Eingabemöglichkeiten für Abfragen

21

Die direkte Ausführung ist auch über die grafische Benutzeroberfläche erreichbar. Wie in der Abbildung zu sehen muss aber auch hier die Designansicht ausgeschaltet sein. Entsprechende Abfrageanweisungen sind teilweise mit SQL gekennzeichnet.
Hier jetzt also die recht umfangreichen Möglichkeiten, an die Datenbank Fragen zu stellen und auf
entsprechendes Ergebnis zu hoffen:
SELECT [{LIMIT <offset> <limit> | TOP <limit>}][ALL | DISTINCT]{ <Select-Formulierung> | "Tabellenname".* | * } [, ...]
[INTO [CACHED | TEMP | TEXT] "neueTabelle"]
FROM "Tabellenliste"[WHERE SQL-Expression][GROUP BY SQL-Expression [, ...]][HAVING SQL-Expression][{ UNION [ALL | DISTINCT] | {MINUS [DISTINCT] | EXCEPT [DISTINCT] } |INTERSECT [DISTINCT] } Abfrageaussage][ORDER BY Ordnungs-Expression [, ...]][LIMIT <limit> [OFFSET <offset>]];[{LIMIT <offset> <limit> | TOP <limit>}]:Hiermit wird die Menge der anzuzeigenden Datensätze begrenzt. Mit LIMIT 10 20 werden
ab dem 11. Datensatz die folgenden 20 Datensätze angezeigt. Mit TOP 10 werden immer die
ersten 10 angezeigt. Dies ist gleichbedeutend mit LIMIT 0 10. LIMIT 10 0 lässt die ersten
10 Datensätze aus und zeigt alle Datensätze ab dem 11. Datensatz an.
Den gleichen Sinn erfüllt die zum Schluss der SELECT-Bedingung erscheinende Formulierung[LIMIT <limit> [OFFSET <offset>]]. LIMIT 10 zeigt lediglich 10 Datensätze an.
Wird OFFSET 20 hinzugefügt, so beginnt die Anzeige ab dem 21. Datensatz. Für die zum
Schluss stehende Begrenzung ist eine Anweisung zur Sortierung (ORDER BY …) oder eine
Bedingung (WHERE …) Voraussetzung.
Sämtliche Begrenzungen des anzuzeigenden Abfrageergebnisses sind bis einschließlich der
Version LO 4.0 nur über die direkte Ausführung des SQL-Kommandos verfügbar. Erst ab LO
4.1 ist eine Limitierung ohne Sortierung oder Bedingung in der grafischen Benutzeroberfläche
möglich. Dies wird sogar dann noch aufrecht erhalten, wenn in den direkten SQL-Modus umgeschaltet wurde. Die Limitierung kann in LO 4.1 in der SQL-Ansicht um den «OFFSET» ergänzt
werden.
Alle Eingaben in der Limitierung können nur direkt als Ganzzahl erfolgen. Es ist nicht möglich,
die Eingaben durch eine Unterabfrage zu ersetzen, so dass z. B. fortlaufend die 5 letzten
Datensätze einer Datenreihe angezeigt werden können.
[ALL | DISTINCT]
SELECT ALL ist die Standardeinstellung. Es werden alle Ergebnisse angezeigt, auf die die
Bedingungen zutreffen. Beispiel:
SELECT ALL "Name" FROM "Tabellenname" gibt alle Namen an; kommt «Peter» dreifachund «Egon» vierfach in der Tabelle vor, so werden die Datensätze eben dreifach oder vierfach
angezeigt. SELECT DISTINCT "Name" FROM "Tabellenname" sorgt hingegen dafür, dassalle Abfrageergebnisse mit gleichem Inhalt unterdrückt werden. Hier würden also «Peter» und«Egon» nur einmal erscheinen. DISTINCT bezieht sich dabei auf den ganzen Datensatz, derin der Abfrage erfasst wird. Wird z. B. auch der Nachname erfasst, so unterscheiden sich die

Eingabemöglichkeiten für Abfragen22

Datensätze mit «Peter Müller» und «Peter Maier». Sie werden also auch bei der Bedingung
DISTINCT auf jeden Fall angezeigt.
<Select-Formulierung>{ Expression | COUNT(*) |{ COUNT | MIN | MAX | SUM | AVG | SOME | EVERY | VAR_POP | VAR_SAMP |STDDEV_POP | STDDEV_SAMP }([ALL | DISTINCT]] Expression) } [[AS] "anzuzeigende Bezeichnung"]
Feldnamen, Berechnungen, Zählen der gesamten Datensätze – alles mögliche Eingaben.
Berechnungen in einer Datenbank können manchmal zu erstaunlichen Ergebnissen
führen. Angenommen in der Datenbank würden Zensuren einer Klassenarbeit verwaltet und mit der Berechnung sollte die Durchschnittszensur ermittelt werden.
Zuerst werden die Zensurenwerte addiert. Die Summe ergibt z. B. 80. Jetzt wird
durch die Zahl der Klassenarbeiten (30) dividiert. Die Abfrage ergibt 2.

HinweisDies liegt daran, dass es sich bei der Berechnung um eine Rechnung mit Feldern
des Typs INTEGER handelt. Auch die Berechnung gibt dann nur Ergebnisse desZahlentyps INTEGER aus. In der Berechnung muss mindestens ein Feld enthaltensein, dass vom Zahlentyp DEZIMAL ist. Dies kann entweder durch Umwandlung mittel einer Funktion der HSQLDB erfolgen oder, einfacher, indem z. B. durch 30.0 dividiert wird. Dann erscheint eine Nachkommsatelle, bei 30.00 zwei Nachkommastellen
usw. Zu beachten ist hier, dass bei Berechnungen Dezimalzahlen mit dem in derenglischen Schreibweise üblichen Dezimalpunkt dargestellt werden. Ein Komma ist
bei Abfragen für die Trennung von Feldern reserviert.

Außerdem stehen in der Felddarstellung auch verschiedene Funktionen zur Verfügung.
Mit Ausnahme von COUNT(*) (zählt alle Datensätze) berücksichtigen die verschiedenen Funktionen keine Felder, die NULL sind.
COUNT | MIN | MAX | SUM | AVG | SOME | EVERY | VAR_POP | VAR_SAMP | STDDEV_POP| STDDEV_SAMP
COUNT("Name") zählt alle Felder, die einen Namen enthalten.
MIN("Name") zeigt den ersten Namen im Alphabet. Das Ergebnis dieser Funktion ist so formatiert, wie es dem Feldinhalt entspricht. Text wird im Ergebnis Text, Ganzzahl zu Ganzzahl,
Dezimalzahl zu Dezimalzahl usw.
MAX("Name") zeigt entsprechend den letzten Namen im Alphabet.
SUM("Zahl") kann nur Werte aus Zahlenfeldern addieren. Auch bei Zeitfeldern versagt die
Funktion.
AVG("Zahl") zeigt den Mittelwert der Inhalte einer Spalte. Auch diese Funktion beschränkt
sich auf Zahlenfelder.
SOME("Ja_Nein"), EVERY("Ja_Nein"): SOME zeigt bei Ja/Nein Feldern (boolschen Feldern) die Version an, die nur einige Felder erfüllen. Da ein boolsches Feld die Werte 0 und 1
wiedergibt erfüllen nur einige (SOME) die Bedingung 1, aber jeder (EVERY) mindestens die
Bedingung 0. Über eine gesamte Tabelle abgefragt wird bei SOME also immer «Ja» erscheinen, wenn mindestens 1 Datensatz mit «Ja» angekreuzt ist. EVERY wird so lange «Nein» ergeben, bis alle Datensätze mit «Ja» angekreuzt sind. Beispiel:
SELECT"Klasse",EVERY("Schwimmer")
FROM "Tabelle1"
GROUP BY "Klasse";

Eingabemöglichkeiten für Abfragen

23

Die Klassen werden alle angezeigt. Erscheint irgendwo kein Kreuz für «Ja», so muss auf jeden
Fall eine Betreuung für das Nichtschwimmerbecken im Schwimmunterricht dabei sein, denn es
gibt mindestens eine Person in der Klasse, die nicht schwimmen kann.
VAR_POP | VAR_SAMP | STDDEV_POP | STDDEV_SAMP sind statistische Funktionen und
greifen nur bei Ganzzahl- und Dezimalzahlfeldern.
Alle Funktionen ergeben 0, wenn die Werte einer Gruppe alle gleich sind.
Die statistischen Funktionen erlauben nicht die Einschränkung von DISTINCT. Sie rechnen
also grundsätzlich über alle Werte, die die Abfrage beinhaltet. DISTINCT hingegen würde
Datensätze mit gleichen Werten von der Anzeige ausschließen.
[AS] "anzuzeigende Bezeichnung": Den Feldern kann in der Abfrage eine andere
Bezeichnung (Alias) gegeben werden.
"Tabellenname".* | * [, ...]
Jedes anzuzeigende Feld kann mit seinem Feldnamen, getrennt durch Komma, angegeben
werden. Werden Felder aus mehreren Tabellen in der Abfrage aufgeführt, so ist zusätzlich eine
Kombination mit dem Tabellennamen notwendig: "Tabellenname"."Feldname".
Statt einer ausführlichen Formulierung kann auch der gesamte Inhalt einer Tabelle angezeigt
werden. Hierfür steht das Symbol «*». Die Nennung des Tabellennamen ist dann nicht erforderlich, da sich das Ergebnis sowieso nur auf eine Tabelle bezieht.
[INTO [CACHED | TEMP | TEXT] "neueTabelle"]
Das Ergebnis dieser Abfrage soll direkt in eine neue Tabelle geschrieben werden. Die neue
Tabelle wird hier benannt. Die Definition der Feldeigenschaften der neuen Tabelle wird dabei
aus der Definition der Felder, die in der Abfrage erhalten sind, erstellt.
Das Schreiben in eine Tabelle funktioniert nicht vom Abfrageeditor aus, da dieser nur anzeigbare Ergebnisse liefert. Hier muss die Eingabe über Extras → SQL erfolgen. Die Tabelle, dieentsteht, ist anschließend erst einmal nicht editierbar, da ein Primärschlüsselfeld fehlt.
Standardmäßig wird der Inhalt in eine Tabelle des Typs CACHED geschrieben, der dem Typ deranderen Tabellen entspricht. Der Typ TEMP ist, wie bei den Tabellen beschrieben, nur begrenzt
in Base nutzbar. Der Typ TEXT hingegen exportiert den Inhalt der Abfrage in eine kommaseparierte Textdatei, die auch von Tabellenkalkulationsprogrammen eingelesen werden kann. Die
Datei liegt anschließend in dem Verzeichnis, in dem auch die *.odb-Datei der Datenbank liegt.
FROM <Tabellenliste>"Tabellenname 1" [{CROSS | INNER | LEFT OUTER | RIGHT OUTER} JOIN
"Tabellenname 2" ON Expression] [, ...]
Die Tabellen, aus denen die Daten zusammengesucht werden sollen, werden in der Regeldurch Komma getrennt aufgeführt. Die Beziehung der Tabellen zueinander wird anschließend
mit dem Schlüsselwort WHERE definiert.
Werden die Tabellen durch einen JOIN statt durch ein Komma miteinander verbunden, so wird
die Beziehung der Tabellen zueinander direkt nach der jeweils folgenden Tabellen mit dem
Begriff ON beginnend definiert.
Ein einfacher JOIN bewirkt, dass nur die Datensätze angezeigt werden, auf die die Bedingung
in beiden Tabellen zutrifft. Beispiel:
SELECT"Tabelle1"."Name","Tabelle2"."Klasse"
FROM "Tabelle1","Tabelle2"
WHERE "Tabelle1"."KlasseID" = "Tabelle2"."ID"

Eingabemöglichkeiten für Abfragen24

entspricht von der Wirkung her
SELECT"Tabelle1"."Name","Tabelle2"."Klasse"
FROM "Tabelle1"
JOIN "Tabelle2"
ON "Tabelle1"."KlasseID" = "Tabelle2"."ID"Es werden hier die Namen und die dazugehörigen Klassen aufgelistet. Fehlt zu einem Nameneine Klasse, so wird der Name nicht aufgelistet. Fehlen zu einer Klasse Namen, so werdendiese ebenfalls nicht aufgelistet. Der Zusatz INNER bewirkt hierbei keine Änderung.
SELECT"Tabelle1"."Name","Tabelle2"."Klasse"
FROM "Tabelle1"
LEFT JOIN "Tabelle2"
ON "Tabelle1"."KlasseID" = "Tabelle2"."ID"Bei dem Zusatz LEFT würden auf jeden Fall alle Inhalte von "Name" aus "Tabelle1" angezeigt– auch die, zu denen keine "Klasse" existiert. Beim Zusatz RIGHT hingegen würden alle Klassen angezeigt – auch die, zu denen kein Name existiert. Der Zusatz OUTER muss hier nicht
unbedingt mit angegeben werden.
SELECT"Tabelle1"."Spieler1","Tabelle2"."Spieler2"
FROM "Tabelle1" AS "Tabelle1"
CROSS JOIN "Tabelle2" AS "Tabelle2"
WHERE "Tabelle1"."Spieler1" <> "Tabelle2"."Spieler2"
Beim CROSS JOIN müssen auf jeden Fall die Tabellen mit einem Aliasnamen versehen werden, wobei das Hinzufügen des Begriffes AS nicht unbedingt notwendig ist. Es werden einfachalle Datensätze aus der ersten Tabelle mit allen Datensätzen der zweiten Tabelle gekoppelt. So
ergibt die obige Abfrage alle möglichen Paarungen aus der ersten Tabelle mit denen aus derzweiten Tabelle mit Ausnahme der Paarungen, bei denen es sich um gleiche Spieler handelt.
Die Bedingung darf beim CROSS JOIN allerdings keine Verknüpfung der Tabellen mit ON enthalten. Stattdessen können unter WHERE Bedingungen eingegeben werden. Würde hier die
Bedingung genauso formuliert wie beim einfachen JOIN, so wäre das Ergebnis gleich:
SELECT"Tabelle1"."Name","Tabelle2"."Klasse"
FROM "Tabelle1"
JOIN "Tabelle2"
ON "Tabelle1"."KlasseID" = "Tabelle2"."ID"
liefert das gleiche Ergebnis wie
SELECT"Tabelle1"."Name","Tabelle2"."Klasse"
FROM "Tabelle1" AS "Tabelle1"
CROSS JOIN "Tabelle2" AS "Tabelle2"
WHERE "Tabelle1"."KlasseID" = "Tabelle2"."ID"[WHERE SQL-Expression]
Die Standardeinleitung, um Bedingungen für eine genauere Filterung der Daten zu formulieren.
Hier werden in der Regel auch die Beziehungen der Tabellen zueinander definiert, sofern die
Tabellen nicht mit JOIN verbunden sind.
Eingabemöglichkeiten für Abfragen

25

[GROUP BY SQL-Expression [, …]]
Wenn Felder mit einer bestimmten Funktion bearbeitet werden (z. B. COUNT, SUM …), so sindalle Felder, die nicht mit einer Funktion bearbeitet werden aber angezeigt werden sollen, mit
GROUP BY zu einer Gruppe zusammen zu fassen.
Beispiel:
SELECT"Name",
SUM("Einnahme"-"Ausgabe") AS "Saldo"
FROM "Tabelle1"
GROUP BY "Name";
Datensätze mit gleichen Namen werden jetzt aufsummiert. Im Ergebnis wird jeweils Einnahme– Ausgabe ermittelt und darüber die Summe, die jede Person erzielt hat, aufgelistet. Das Feld
wird unter dem Namen Saldo dargestellt.
[HAVING SQL-Expression]
Die HAVING-Formulierung ähnelt sehr der WHERE-Formulierung. Sie kann für Bedingungen eingesetzt, die mit Hilfe von Funktionen wie MIN, MAX formuliert werden. Nur HAVING ist dafürgeeignet, in den Bedingungen auch Berechnungen durchzuführen. HAVING erscheint dabei
nach einer eventuell vorhandenen GROUP BY – Formulierung.
Beispiel:
SELECT"Name","Laufzeit"
FROM "Tabelle1"
GROUP BY "Name","Laufzeit"
HAVING MIN("Laufzeit") < '00:40:00';
Es werden alle Namen und Laufzeiten aufgelistet, bei denen die Laufzeit weniger als 40 Minuten beträgt.
[SQL Expression]
SQL-Ausdrücke werden nach dem folgenden Schema miteinander verbunden:[NOT] Bedingung [{ OR | AND } Bedingung]Beispiel:
SELECT*
FROM "Tabellenname"
WHERE
NOT "Rückgabedatum" IS NULL
AND "LeserID" = 2;
Aus der Tabelle werden die Datensätze ausgelesen, bei denen ein "Rückgabedatum" eingetragen wurde und die "LeserID" 2 lautet. Das würde in der Praxis bedeuten, dass alle Medien, dieeine bestimmte Person ausgeliehen und wieder zurückgegeben hat, damit ermittelt werden
könnten. Die Bedingungen sind nur durch AND miteinander verbunden. Das NOT bezieht sichrein auf die erste Bedingung.
SELECT*
FROM "Tabellenname"
WHERE NOT ("Rückgabedatum" IS NULL AND "LeserID" = 2);
Wird eine Klammer um die Bedingung gesetzt und NOT steht außerhalb der Klammer, so werden genau die Datensätze angezeigt, die die in den Klammern stehenden BedingungenEingabemöglichkeiten für Abfragen26

zusammen komplett nicht erfüllen. Das wären alle Datensätze mit Ausnahme derer, die"LeserID" mit der Nummer 2 noch nicht zurückgegeben hat.
[SQL Expression]: Bedingungen{ Wert [|| Wert]
Ein Wert kann einzeln oder mit mehreren Werten zusammen über zwei senkrechte Striche ||kombiniert werden. Dies gilt dann natürlich auch für Feldinhalte.
SELECT"Nachname" || ', ' || "Vorname" AS "Name"
FROM "Tabellenname"
Die Inhalte aus den Feldern "Nachname" und "Vorname" werden in einem Feld "Name"gemeinsam angezeigt. Dabei wird ein Komma und eine Leertaste zwischen "Nachname" und"Vorname" eingefügt.
| Wert { = | < | <= | > | >= | <> | != } Wert
Die Zeichen entsprechend den aus der Mathematik bekannten Operatoren:{ Gleich | Kleiner als | Kleiner oder gleich | Größer als | Größer oder gleich | nicht gleich | nicht
gleich }| Wert IS [NOT] NULL
Das entsprechende Feld hat keinen Inhalt, ist auch nicht beschrieben worden. Dies kann in der
GUI nicht unbedingt beurteilt werden, denn ein leeres Textfeld bedeutet noch nicht, dass das
Feld völlig ohne Inhalt ist. Die Standardeinstellung von Base ist aber so, dass leere Felder inder Datenbank auf NULL gesetzt werden.
| EXISTS(Abfrageaussage)
Beispiel:
SELECT"Name"FROM "Tabelle1"
WHERE EXISTS(SELECT"Vorname"
FROM "Tabelle2"
WHERE "Tabelle2"."Vorname" = "Tabelle1"."Name")
Es werden die Namen aus Tabelle1 aufgeführt, die als Vornamen in Tabelle2 verzeichnet sind.
| Wert BETWEEN Wert AND Wert
BETWEEN Wert1 AND Wert2 gibt alle Werte ab Wert1 bis einschließlich Wert2 wieder. Werden hier Buchstaben als Werte eingesetzt, so wird die alphabetische Sortierung angenommen,
wobei Kleinbuchstaben und Großbuchstaben die gleichen Werte haben.
SELECT"Name"FROM "Tabellenname"
WHERE "Name" BETWEEN 'A' AND 'E';
Diese Abfrage gibt alle Namen wieder, die mit A, B, C und D beginnen (ggf. auch mit entsprechendem Kleinbuchstaben). Da als unterer Begrenzung E gesetzt wurde sind alle Namen mit E
nicht mehr in der Auswahl enthalten. Der Buchstabe E würde in einer Sortierung ganz am
Anfang der Namen mit E stehen.
| Wert [NOT] IN ( {Wert [, ...] | Abfrageaussage } )Hier wird entweder eine Liste von Werten oder eine Abfrage eingesetzt. Die Bedingung ist
erfüllt, wenn der Wert in der Werteliste bzw. im Abfrageergebnis enthalten ist.

Eingabemöglichkeiten für Abfragen27

| Wert [NOT] LIKE Wert [ESCAPE] Wert }Der LIKE-Operator ist derjenige, der in vielen einfachen Suchfunktionen benötigt wird. Die
Angabe der Werte erfolgt hier nach folgendem Muster:'%' steht für beliebig viele, ggf. auch 0 Zeichen,'_' ersetzt genau ein Zeichen.
Um nach '%' oder '_' selbst zu suchen müssen die Zeichen direkt nach einem zweiten Zeichen
auftauchen, das nach ESCAPE definiert wird.
SELECT"Name"FROM "Tabellenname"
WHERE "Name" LIKE '\_%' ESCAPE '\'Diese Abfrage zeigt alle Namen auf, die mit einem Unterstrich beginnen. Als ESCAPE-Zeichen
ist hier '\' definiert worden.
[SQL Expression]: Werte[+ | -] { Ausdruck [{ + | - | * | / | || } Ausdruck]
Vorzeichen vor den Werten sind möglich. Die Addition, Subtraktion, Multiplikation, Division undVerkettung von Ausdrücken ist erlaubt. Beispiel für eine Verkettung:
SELECT"Nachname"||', '||"Vorname"
FROM "Tabelle"
Auf diese Art und Weise werden Datensätze in der Abfrage als ein Feld ausgegeben, in der"Nachname, Vorname" steht. Die Verkettung erlaubt also jeden der weiter unten genannten
Ausdrücke.
| ( Bedingung )Siehe hierzu den vorhergehenden Abschnitt| Funktion ( [Parameter] [,...] )Siehe hierzu im Anhang das Kapitel «Eingebaute Funktionen und abgespeicherte
Prozeduren».
Die folgenden Abfragen werden auch als Unterabfragen (Subselects) bezeichnet.
| Abfrageaussage, die nur genau einen Wert ergibt
Da ein Datensatz für jedes Feld nur einen Wert darstellen kann, kann auch nur die Abfrage
komplett angezeigt werden, die genau einen Wert ergibt.
| {ANY|ALL} (Abfrageaussage, die den Inhalt einer ganzen Spalte
wiedergibt)
Manchmal gibt es Bedingungen, bei denen ein Ausdruck mit einer ganzen Gruppe von Werten
verglichen wird. Zusammen mit ANY bedeutet das, dass der Ausdruck mindestens einmal in derGruppe vorkommen muss. Dies ließe sich auch mit der IN-Bedingung beschreiben. = ANYergibt das gleiche Ergebnis wie IN.
Zusammen mit ALL bedeutet dies, dass alle Werte der Gruppe dem einen Ausdruck entsprechen müssen.
[SQL Expression]: Ausdrücke{ 'Text' | Ganzzahl | Fließkommazahl| ["Tabelle".]"Feld" | TRUE | FALSE | NULL }Als Grundlage dienen Werte, die, abhängig vom Quellformat, mit unterschiedlichen Ausdrücken
angegeben werden. Wird nach Textinhalten gesucht, so ist der Inhalt in Hochkommata zu setzen. Ganzzahlen werden ohne Hochkommata geschrieben, ebenso Fließkommazahlen (statt

Eingabemöglichkeiten für Abfragen28

Komma ist in SQL direkt der Dezimalpunkt zu setzen).
Felder stehen für die Werte, die sich in den Feldern einer Tabelle befinden. Meist werden entweder Felder miteinander verglichen oder Felder mit Werten. In SQL werden die Feldbezeichnungen besser in doppelte Anführungsstriche gesetzt, da sonst eventuell Feldbezeichnungennicht richtig erkannt werden. Üblicherweise geht SQL ohne doppelte Anführungsstriche davonaus, dass alles ohne Sonderzeichen, in einem Wort und mit Großbuchstaben geschrieben ist.
Sind mehrere Tabellen in der Abfrage enthalten, so ist neben dem Feld auch die Tabelle, vom
Feld getrennt durch einen Punkt, aufzuführen.
TRUE und FALSE stammen üblicherweise von Ja/Nein-Feldern.
NULL bedeutet, dass nichts angegeben wurde. Es ist nicht gleichbedeutend mit 0, sondern
eher mit Leer.
UNION [ALL | DISTINCT] Abfrageaussage SQL
Hiermit werden Abfragen so verknüpft, dass der Inhalt der 2. Abfrage unter die erste Abfragegeschrieben wird. Dazu müssen alle Felder der beiden Abfragen vom Typ her übereinstimmen.
Diese Verknüpfung von mehreren Abfragen funktioniert nur über die direkte Ausführung des
SQL-Kommandos.
SELECT"Vorname"
FROM "Tabelle1"
UNION DISTINCT
SELECT"Vorname"
FROM "Tabelle2";
Diese Abfrage liefert alle Vornamen aus Tabelle1 und Tabelle2; der Zusatz DISTINCT zeigt an,
dass keine doppelten Vornamen ausgegeben werden. DISTINCT ist in diesem Zusammenhang die Standardeinstellung. Die Vornamen sind dabei standardmäßig nach dem Alphabet
aufsteigend sortiert. Mit ALL werden einfach alle Vornamen der Tabelle1 angezeigt gefolgt vonden Vornamen Tabelle2. Sie sind jetzt standardmäßig nach dem Primärschlüssel sortiert.
MINUS [DISTINCT] | EXCEPT [DISTINCT] Abfrageaussage
SELECT"Vorname"
FROM "Tabelle1"
EXCEPT
SELECT"Vorname"
FROM "Tabelle2";
Zeigt alle Vornamen aus Tabelle1 mit Ausnahme der Vornamen an, die in Tabelle 2 enthaltensind. MINUS und EXCEPT führen zum gleichen Ergebnis. Sortierung ist alphabetisch. Dies funktioniert zur Zeit nur, wenn das SQL-Kommando direkt ausgeführt wird.
INTERSECT [DISTINCT] Abfrageaussage
SELECT"Vorname"
FROM "Tabelle1"
INTERSECTSELECT"Vorname"
FROM "Tabelle2";
Hier werden nur die Vornamen angezeigt, die in beiden Tabellen vorhanden sind. Die Sortierung ist wieder alphabetisch. Dies funktioniert zur Zeit nur, wenn das SQL-Kommando direkt
ausgeführt wird.

Eingabemöglichkeiten für Abfragen

29

[ORDER BY Ordnungs-Expression [, …]]Hier können Feldnamen, die Nummer der Spalte (beginnend mit 1 von links), ein Alias (formuliert z. B. mit AS) oder eine Wertzusammenführung (siehe [SQL Expression]: Werte) angegeben werden. Die Sortierung erfolgt in der Regel aufsteigend (ASC). Nur wenn die Sortierung
absteigend erfolgen soll muss DESC angegeben werden.
SELECT"Vorname","Nachname" AS "Name"
FROM "Tabelle1"
ORDER BY "Nachname";
ist identisch mit
SELECT"Vorname","Nachname" AS "Name"
FROM "Tabelle1"
ORDER BY "Nachname" ASC;
ist identisch mit
SELECT"Vorname","Nachname" AS "Name"
FROM "Tabelle1"
ORDER BY "Name";

Verwendung eines Alias in Abfragen
Durch Abfragen können auch Felder in einer anderen Bezeichnung wiedergegeben werden.
SELECT"Vorname","Nachname" AS "Name"
FROM "Tabelle1"
Dem Feld Nachname wird in der Anzeige die Bezeichnung Name zugeordnet.
Wird eine Abfrage aus zwei Tabellen erstellt, so steht vor den jeweiligen Feldbezeichnungen derName der Tabelle:
SELECT"Tabelle1"."Vorname","Tabelle1"."Nachname" AS "Name","Tabelle2"."Klasse"
FROM "Tabelle1","Tabelle2"
WHERE "Tabelle1"."Klasse_ID" = "Tabelle2"."ID"
Auch den Tabellennamen kann ein Aliasname zugeordnet werden, der allerdings in der Tabellenansicht nicht weiter erscheint. Wird so ein Alias zugeordnet, so müssen sämtliche Tabellenbezeichnungen in der Abfrage entsprechend ausgetauscht werden:
SELECT"a"."Vorname","a"."Nachname" AS "Name","b"."Klasse"
FROM "Tabelle1" AS "a","Tabelle2" AS "b"
WHERE "a"."Klasse_ID" = "b"."ID"
Verwendung eines Alias in Abfragen

30

Die Zuweisung eines Aliasnamens bei Tabellen kann auch verkürzt ohne den Zuweisungsbegriff
AS erfolgen:
SELECT"a"."Vorname","a"."Nachname" AS "Name","b"."Klasse"
FROM "Tabelle1" "a","Tabelle2" "b"
WHERE "a"."Klasse_ID" = "b"."ID"
Dies erschwert allerdings die eindeutige Lesbarkeit des Codes. Daher sollte nur in Ausnahmefällen
auf die Verkürzung zurückgegriffen werden.

Abfragen für die Erstellung von Listenfeldern
In Listenfeldern wird ein Wert angezeigt, der nicht an die den Formularen zugrundeliegenden
Tabellen weitergegeben wird. Sie werden schließlich eingesetzt, um statt eines Fremdschlüssels
zu sehen, welchen Wert der Nutzer damit verbindet. Der Wert, der schließlich in Formularen abgespeichert wird, darf bei den Listenfeldern nicht an der ersten Position stehen.
SELECT"Vorname","ID"
FROM "Tabelle1";
Diese Abfrage würde alle Vornamen anzeigen und den Primärschlüssel "ID" an die dem Formularzugrundeliegende Tabelle weitergeben. So ist das natürlich noch nicht optimal. Die Vornamen
erscheinen unsortiert; bei gleichen Vornamen ist außerdem unbekannt, um welche Person es sichdenn handelt.
SELECT"Vorname"||' '||"Nachname","ID"
FROM "Tabelle1"
ORDER BY "Vorname"||' '||"Nachname";
Jetzt erscheint der Vorname, getrennt von dem Nachnamen, durch ein Leerzeichen. Die Namenwerden unterscheidbarer und sind sortiert. Die Sortierung erfolgt der Logik, dass natürlich nachden vorne stehenden Buchstaben zuerst sortiert wird, also Vornamen zuerst, dann Nachnamen.
Andere Sortierreihenfolgen als nach der Anzeige des Feldes würden erst einmal verwirren.
SELECT"Nachname"||', '||"Vorname","ID"
FROM "Tabelle1"
ORDER BY "Nachname"||', '||"Vorname";
Dies würde jetzt zu der entsprechenden Sortierung führen, die eher unserer Gewohnheit entspricht. Familienmitglieder erscheinen zusammen untereinander, bei gleichen Nachnamen und
unterschiedlichen Familien wird allerdings noch durcheinander gewürfelt. Um dies zu unterscheiden müsste eine Gruppenzuordnung in der Tabelle gemacht werden.
Letztes Problem ist noch, dass eventuell auftauchende Personen mit gleichem Nachnamen undgleichem Vornamen nicht unterscheidbar sind. Variante 1 wäre, einfach einen Namenszusatz zu
entwerfen. Aber wie sieht das denn aus, wenn ein Anschreiben mit Herr «Müller II» erstellt wird?
SELECT"Nachname"||', '||"Vorname"||' - ID:'||"ID","ID"

Abfragen für die Erstellung von Listenfeldern

31

FROM "Tabelle1"
ORDER BY "Nachname"||', '||"Vorname"||"ID";Hier wird auf jeden Fall jeder Datensatz unterscheidbar. Angezeigt wird «Nachname, Vorname –ID:IDWert».
Im Formular Ausleihe wurde ein Listenfeld erstellt, das lediglich die Medien darstellen sollte, dienoch nicht entliehen wurden. Dies wird über die folgende SQL-Formulierung möglich:
SELECT"Titel" || ' - Nr. ' || "ID","ID"
FROM "Medien"
WHERE "ID"NOT IN(SELECT"Medien_ID"
FROM "Ausleihe"
WHERE "Rueck_Datum" IS NULL)ORDER BY "Titel" || ' - Nr. ' || "ID" ASC
Das folgende Listenfeld stellt die Inhalte mehrerer Felder in Tabellenform dar:Damit so eine Darstellung gelingt muss zuerst einmal eine entsprechende nicht proportionale
Schrift ausgewählt werden. Courier oder alle Mono-Schriftarten wie z.B. Liberation Mono können
hier genutzt werden. Die Darstellung in tabellarischer Form gelingt über den SQL-Code:
SELECT
LEFT("Ware"||'',25) || ' - ' ||RIGHT(''||"Preis",8) || ' €',"ID"
FROM "Waren"
ORDER BY ("Ware" || ' - ' || "Preis" || ' €') ASC
An den Inhalt des Feldes "Ware" werden entsprechend viele Leerzeichen angehängt, so dass"Ware" zusammen mit den Leerzeichen eine Mindestlänge von 25 Zeichen hat. Anschließend werden die ersten 25 Buchstaben dargestellt, die überflüssigen Leerzeichen also abgeschnitten.
Die Anzahl der notwendigen Leerzeichen kann übrigens auch per Abfrage ermittelt werden. So
wird vermieden, dass doch einmal ein Wert aus "Ware" in seiner Länge beschnitten wird.
SELECT
LEFT("Ware"||SPACE((SELECT MAX(LENGTH("Ware")) FROM "Waren")),(SELECT MAX(LENGTH("Ware")) FROM "Waren"))|| ' - ' ||RIGHT(''||"Preis",8) || ' €',"ID"
FROM "Waren"
ORDER BY ("Ware" || ' - ' || "Preis" || ' €') ASC

Abfragen für die Erstellung von Listenfeldern

32

Da der Preis rechtsbündig dargestellt werden soll wird hier vor dem Preis mit Leerzeichen aufgefüllt und entsprechend maximal 8 Zeichen von rechts aus dargestellt. Die angestrebte Darstellung
reicht also für alle Preise bis 99999,99 € aus.
Soll auch noch der Punkt aus der SQL-Darstellung durch ein Komma ersetzt werden, so ist der
SQL-Code entsprechend zu ergänzen. Dies wäre überREPLACE(RIGHT(''||"Preis",8),'.',',')

möglich.

Abfragen als Grundlage von Zusatzinformationen in
Formularen
Will man zusätzliche Informationen im Formular im Auge haben, die so gar nicht sichtbar wären, so
bieten sich verschiedene Abfragemöglichkeiten an. Die einfachste ist, mit gesonderten Abfragen
diese Informationen zu ermitteln und in andere Formulare einzustellen. Der Nachteil dieser Variante kann sein, dass sich Datenänderungen auf das Abfrageergebnis auswirken würden, aber leider die Änderungen nicht automatisch angezeigt werden.
Hier ein Beispiel aus dem Bereich der Warenwirtschaft für eine einfache Kasse:
Die Tabelle für eine Kasse enthält Anzahl und Fremdschlüssel von Waren, außerdem eine Rechnungsnummer. Besonders wenig Informationen erhält der Nutzer an der Supermarktkasse, wennkeine zusätzlichen Abfrageergebnisse auf den Kassenzettel gedruckt werden. Schließlich werden
die Waren nur über den Barcode eingelesen. Ohne Abfrage ist im Formular nur zusehen:AnzahlBarcode

3

17

2

24

usw.
Was sich hinter den Nummern versteckt kann nicht mit einem Listenfeld sichtbar gemacht werden,
da ja der Fremdschlüssel über den Barcode direkt eingegeben wird. So lässt sich auch nicht überdas Listenfeld neben der Ware zumindest der Einzelpreis ersehen.
Hier hilft eine Abfrage:
SELECT"Kasse"."RechnungID","Kasse"."Anzahl","Ware"."Ware","Ware"."Einzelpreis","Kasse"."Anzahl"*"Ware"."Einzelpreis" AS "Gesamtpreis"
FROM "Kasse","Ware"
WHERE "Ware"."ID" = "Kasse"."WareID";
Jetzt ist zumindest schon einmal nach der Eingabe die Information da, wie viel denn für
3 * Ware'17' zu bezahlen ist. Außerdem werden nur die Informationen durch das Formular zu filternsein, die mit der entsprechenden "RechnungID" zusammenhängen. Was auf jeden Fall noch fehlt
ist das, was denn der Kunde nun bezahlen muss:
SELECT"Kasse"."RechnungID",
SUM("Kasse"."Anzahl"*"Ware"."Einzelpreis") AS "Summe"
FROM "Kasse","Ware"

Abfragen als Grundlage von Zusatzinformationen in Formularen

33

WHERE "Ware"."ID" = "Kasse"."WareID"
GROUP BY "Kasse"."RechnungID";
Für das Formular liefert diese Abfrage nur eine Zahl, da über das Formular natürlich wieder die"RechnungID" gefiltert wird, so dass ein Kunde nicht gleichzeitig sieht, was andere vor ihm eventuell gezahlt haben.

Eingabemöglichkeit in Abfragen
Um Eingaben in Abfragen zu tätigen muss der Primärschlüssel für die jeweils zugrundeliegende
Tabelle in der Abfrage enthalten sein.

Bei der Ausleihe von Medien ist es z. B. nicht sinnvoll, für einen Leser auch die Medien noch anzeigen zu lassen, die längst zurückgegeben wurden.
SELECT"ID","LeserID","MedienID","Ausleihdatum"
FROM "Ausleihe"
WHERE "Rückgabedatum" IS NULL;
So lässt sich im Formular innerhalb eines Tabellenkontrollfeldes all das anzeigen, was ein
bestimmter Leser zur Zeit entliehen hat. Auch hier ist die Abfrage über entsprechende Formularkonstruktion (Leser im Hauptformular, Abfrage im Unterformular) zu filtern, so dass nur die tatsächEingabemöglichkeit in Abfragen34

lich entliehenen Medien angezeigt werden. Die Abfrage ist zur Eingabe geeignet, da der Primärschlüssel in der Abfrage enthalten ist.
Die Abfrage wird dann nicht mehr editierbar, wenn sie aus mehreren Tabellen besteht und die
Tabellen über einen Alias-Namen angesprochen werden. Dabei ist es unerheblich, ob die Primärschlüssel in der Abfrage enthalten sind.

SELECT"Medien"."ID","Medien"."Titel","Medien"."Kategorie_ID","Kategorie"."ID" AS "katID""Kategorie"."Kategorie",
FROM "Medien","Kategorie"
WHERE "Medien"."Kategorie_ID" = "Kategorie"."ID";
Diese Abfrage bleibt editierbar, da beide Primärschlüssel enthalten sind und auf die Tabellennicht mit einem Alias zugegriffen wird. Auch bei einer Abfrage, die mehrere Tabellen miteinander
verknüpft, müssen lediglich alle Primärschlüssel vorhanden sein.

Eingabemöglichkeit in Abfragen35

Es ist allerdings nicht möglich, in einer Abfrage, die auf mehreren Tabellen beruht, das Fremdschlüsselfeld der einen Tabelle, das sich auf die andere Tabelle bezieht, zu ändern. Im angezeigten Datensatz wurde versucht, die Kategorie für den Titel «Der kleine Hobbit» umzustellen. Das
Feld "Kategorie_ID" wurde von '0' auf '2' geändert. Die Änderung schien vollzogen, die neue Kategorie erschien auch. Das Speichern war dann aber nicht möglich.
Allerdings ist es möglich, den Inhalt von "Kategorie" selbst zu bearbeiten, also z.B. 'Fantasy' zum
Begriff 'Fantasie' zu ändern. Das ändert dann allerdings diesen Begriff für die Kategorie, betrifft
also alle damit verbundenen Datensätze.
SELECT"a"."ID","a"."Titel","Kategorie"."Kategorie","Kategorie"."ID" AS "katID"
FROM "Medien" AS "a","Kategorie"
WHERE "a"."Kategorie_ID" = "Kategorie"."ID";In dieser Abfrage wird auf die Tabelle "Medien" mit einem Alias zugegriffen. Sie wird jetzt nicht
editierbar sein.
In dem obigen Beispiel ist das leicht vermeidbar. Wenn aber eine Korrelierte Unterabfrage gestellt
wird, so muss mit einem Tabellenalias gearbeitet werden. So eine Abfrage mit Alias kann nur
dann editierbar bleiben, wenn sie lediglich eine Tabelle in der Hauptabfrage enthält.

Eingabemöglichkeit in Abfragen36

In der Design-Ansicht erscheint hier lediglich eine Tabelle. Die Tabelle "Medien" ist mit einem Alias
versehen, damit auf die Inhalte des Feldes "Kategorie_ID" mit der korrelierenden Unterabfrage
zugegriffen werden kann.
In so einer Abfrage ist es jetzt möglich, das Fremdschlüsselfeld "Kategorie_ID" auf eine andere
Kategorie umzustellen. In dem obigen Beispiel wurde das Feld "Kategorie_ID" von '0' auf '2' geändert. Dem "Titel" 'Der kleine Hobbit' wurde so die "Kategorie" 'Liedermacher' zugeordnet.

Allerdings ist es jetzt nicht mehr möglich, einen Wert in dem Feld zu ändern, das seinen Inhalt überdie korrelierende Unterabfrage erhält. Die Änderung der "Kategorie" von 'Fantasy' in 'Fantasie' wird
erst einmal angezeigt. Die Änderung wird allerdings nicht registriert und ist auch nicht abspeicherbar. In der Tabelle, die die Design-Ansicht anzeigt, ist das Feld "Kategorie" schließlich nicht enthalten.
Eingabemöglichkeit in Abfragen37

Verwendung von Parametern in Abfragen
Wird viel mit gleichen Abfragen, aber eventuell unterschiedlichen Werten als Voraussetzung zu
diesen Abfragen gearbeitet, so sind Parameterabfragen möglich. Vom Prinzip her funktionieren
Parameterabfragen erst einmal genauso wie Abfragen, die in Unterformularen abgelegt werden:
SELECT"ID","LeserID","MedienID","Ausleihdatum"
FROM "Ausleihe"
WHERE "Rückgabedatum" IS NULL
AND "LeserID"=2;
Diese Abfrage zeigt nur die entliehenen Medien des Lesers mit der Nummer 2 an.
SELECT"ID","LeserID","MedienID","Ausleihdatum"
FROM "Ausleihe"
WHERE "Rückgabedatum" IS NULL
AND "LeserID" = :Lesernummer;
Jetzt erscheint beim Aufrufen der Abfrage ein Eingabefeld. Es fordert zur Eingabe einer Lesernummer auf. Wird hier ein Wert eingegeben, so werden die zur Zeit entliehenen Medien dieses Lesers
angezeigt.
SELECT"Ausleihe"."ID","Leser"."Nachname"||', '||"Leser"."Vorname","Ausleihe"."MedienID","Ausleihe"."Ausleihdatum"
FROM "Ausleihe", "Leser"
WHERE "Ausleihe"."Rückgabedatum" IS NULL
AND "Leser"."ID" = "Ausleihe"."LeserID"
AND "Leser"."Nachname" LIKE '%' || :Lesername || '%'ORDER BY "Leser"."Nachname"||', '||"Leser"."Vorname" ASC;
Diese Abfrage ist noch deutlich komfortabler als die vorhergehende. Jetzt muss nicht eine Nummer
des Lesers bekannt sein. Es reicht die Eingabe eines Teils des Nachnamen des Lesers und alle
Medien von Lesern, auf die diese Beschreibung zutrifft, werden angezeigt.
Wird"Leser"."Nachname" LIKE '%' || :Lesername || '%'durch
LOWER("Leser"."Nachname") LIKE '%' || LOWER( :Lesername ) || '%'ersetzt, so ist es auch noch egal, ob die Namen groß oder klein geschrieben sind.
Wird der Parameter in der obigen Abfrage leer gelassen, so werden alle Leser angezeigt. Solldies vermieden werden, so muss etwas in die Trickkiste gegriffen werden:
LOWER ("Leser"."Nachname") LIKE '%' || IFNULL( NULLIF ( LOWER(:Lesername), '' ), '§§' ) || '%'Das leere Parameterfeld gibt an die Abfrage einen leeren String, aber nicht NULL weiter. Deshalbmuss erst einmal dem leeren Parameterfeld die Eigenschaft NULL mit NULLIF zugewiesen werden. Anschließend wird für den Fall, dass eben die Parametereingabe jetzt NULL ergibt, dieser
Verwendung von Parametern in Abfragen38

Eingabe ein Wert zugewiesen, der in der Regel in keinem der Datensätze vorkommt. In dem obigen Beispiel ist das '§§'. Dieser Wert wird mit der Abfrage entsprechend auch nicht gefunden.
Ein Parameter kann bei Formularen auch von einem Hauptformular an ein Unterformular weitergegeben werden. Es kann allerdings passieren, dass Parameterabfragen in Unterformularen nicht
aktualisiert werden, wenn Daten geändert oder neu eingegeben werden.
Manchmal wäre es wünschenswert, Listenfelder in Abhängigkeit von Einstellungen des Hauptformulars zu ändern. So könnte beispielsweise ausgeschlossen werden, dass in einer Bibliothek
Medien an Personen entliehen werden, die zur Zeit keine Medien ausleihen dürfen. Leider ist abereine derartige Listenfelderstellung in Abhängigkeit von der Person über Parameter nicht möglich.

Unterabfragen
Unterabfragen, die in Felder eingebaut werden, dürfen immer nur genau einen Datensatz wiedergeben. Das Feld kann schließlich auch nur einen Wert wiedergeben.
SELECT"ID","Einnahme","Ausgabe",( SELECT
SUM( "Einnahme" ) - SUM( "Ausgabe" )FROM "Kasse")
AS "Saldo"
FROM "Kasse";
Diese Abfrage ist eingabefähig (Primärschlüssel vorhanden). Die Unterabfrage liefert nur genau
einen Wert, nämlich die Gesamtsumme. Damit lässt sich nach jeder Eingabe der Kassenstandablesen. Dies ist noch nicht vergleichbar mit der Supermarktkasse aus Abfragen als Grundlage
von Zusatzinformationen in Formularen. Es fehlt natürlich die Einzelberechnung aus Anzahl * Einzelpreis, aber auch die Berücksichtigung von Rechnungsnummer. Es wird immer die Gesamtsumme ausgegeben. Zumindest die Rechnungsnummer lässt sich über eine Parameterabfrage
einbauen:
SELECT"ID","Einnahme","Ausgabe",( SELECT
SUM( "Einnahme" ) - SUM( "Ausgabe" )FROM "Kasse"
WHERE "RechnungID" = :Rechnungsnummer)
AS "Saldo"
FROM "Kasse"
WHERE "RechnungID" = :Rechnungsnummer;
Bei einer Parameterabfrage muss der Parameter in beiden Abfrageanweisungen gleich sein, wenner als ein Parameter verstanden werden soll.
Für Unterformulare können diese Parameter mitgegeben werden. Unterformulare erhalten dannstatt der Feldbezeichnung die darauf bezogene Parameterbezeichnung. Die Eingabe dieser Verknüpfung ist nur in den Eigenschaften der Unterformulare, nicht über den Assistenten möglich.

HinweisUnterabfragen

Unterformulare, die auf Abfragen beruhen, werden nicht in Bezug auf die Parameter
automatisch aktualisiert. Es bietet sich also eher an, den Parameter direkt aus dem
darüber liegenden Formular weiter zu geben.

39Korrelierte Unterabfrage
Mittels einer noch verfeinerten Abfrage lässt sich innerhalb einer bearbeitbaren Abfrage sogar derlaufende Kontostand mitführen:
SELECT"ID","Einnahme","Ausgabe",( SELECT
SUM( "Einnahme" ) - SUM( "Ausgabe" )FROM "Kasse"
WHERE "ID" <= "a"."ID" )AS "Saldo"
FROM "Kasse" AS "a"
ORDER BY "ID" ASC
Die Tabelle "Kasse" ist gleichbedeutend mit der Tabelle "a". "a" stellt aber nur den Bezug zu den indiesem Datensatz aktuellen Werten her. Damit ist der aktuelle Wert von "ID" aus der äußeren
Abfrage innerhalb der Unterabfrage auswertbar. Auf diese Art und Weise wird in Abhängigkeit vonder "ID" der jeweilige Saldo zu dem entsprechenden Zeitpunkt ermittelt, wenn einfach davon ausgegangen wird, dass die "ID" über den Autowert selbständig hoch geschrieben wird.

HinweisSoll nach den Inhalten der Unterabfrage mit Hilfe der Filterfunktionen des Abfrageeditors gefiltert werden, so funktioniert dies zur Zeit nur, wenn statt der einfachen
Klammern zu Beginn und Ende der Unterabfrage die Klammern doppelt gesetzt werden: « ((SELECT ….)) AS "Saldo" »Abfragen als Bezugstabellen von Abfragen
In einer Abfrage soll für alle Leser, bei denen eine 3. Mahnung zu einem Medium vorliegt, ein
Sperrvermerk ausgegeben werden.
SELECT"Ausleihe"."Leser_ID",'3 Mahnungen - der Leser ist gesperrt' AS "Sperre"
FROM(SELECT COUNT( "Datum" ) AS "Anzahl","Ausleihe_ID"
FROM "Mahnung"
GROUP BY "Ausleihe_ID")
AS "a","Ausleihe"
WHERE "a"."Ausleihe_ID" = "Ausleihe"."ID"AND "a"."Anzahl" > 2
Zuerst wird die innere Abfrage konstruiert, auf die sich die äußere Abfrage bezieht. In dieser
Abfrage wird die Anzahl der Datumseinträge, gruppiert nach dem Fremdschlüssel "Ausleihe_ID",
ermittelt. Dies muss unabhängig von der "Leser_ID" geschehen, da sonst nicht nur 3 Mahnungenbei einem Medium, sondern auch drei Medien mit einer ersten Mahnung zusammengezählt würden. Die innere Abfrage wird mit einem Alias versehen, damit sie mit der "Leser_ID" der äußeren
Abfrage in Verbindung gesetzt werden kann.
Die äußere Abfrage bezieht sich in diesem Fall nur in der Bedingungsformulierung auf die innere
Abfrage. Sie zeigt nur dann eine "Leser_ID" und den Text zur "Sperre" an, wenn "Ausleihe"."ID"und "a"."Ausleihe_ID" gleich sind sowie "a"."Anzahl" > 2 ist.

Abfragen als Bezugstabellen von Abfragen40

Prinzipiell stehen der äußeren Abfrage alle Felder der inneren Abfrage zur Verfügung. So ließe sichbeispielsweise die Anzahl mit "a"."Anzahl" in der äußeren Abfrage einblenden, damit auch die tatsächliche Mahnzahl erscheint.
Es kann allerdings sein, dass im Abfrageeditor die grafische Benutzeroberfläche nach so einer
Konstruktion nicht mehr verfügbar ist. Soll die Abfrage anschließend wieder zum Bearbeiten geöffnet werden, so erscheint die folgende Meldung:

Ist die Abfrage dann in der SQL-Ansicht zum Bearbeiten geöffnet und wird versucht von dort in die
grafische Ansicht zu wechseln, so erscheint die Fehlermeldung

Die grafische Benutzeroberfläche findet also nicht das in der inneren Abfrage enthaltene Feld
"Ausleihe_ID", mit dem die Beziehung von innerer und äußerer Abfrage geregelt wird.
Wird die Abfrage allerdings aufgerufen, so wird der entsprechende Inhalt anstandslos wiedergegeben. Es muss also nicht der direkte SQL-Mode bemüht werden. Damit stehen auch die Sortierund Filterfunktionen der grafischen Benutzeroberfläche weiter zur Verfügung.
Die folgenden Screenshots zeigen, wie der unterschiedliche Weg zu einem Abfrageergebnis mit
Unterabfragen auch verlaufen kann. Hier soll in der Abfrage einer Rechnungsdatenbank ermittelt
werden, was der Kunde an der Kasse letztlich zahlen muss. Die Preise werden multipliziert mit derAnzahl der entsprechenden Ware zum "Teilbetrag". Außerdem soll auch noch die Summe der Teilbeträge ausgegeben werden. Und all das soll editierbar bleiben, damit die Abfrage als Grundlage
für ein Formular dienen kann.

Abfragen als Bezugstabellen von Abfragen

41

Abbildung 5: Abfrage über zwei Tabellen. Damit die Abfrage
editierbar bleibt, muss aus beiden Tabellen der Primärschlüssel
in der Abfrage enthalten sein.

Abbildung 6: Die Tabelle "Ware" wurde in eine
Unterabfrage verschoben. Diese Unterabfrage wird
im Tabellenbereich (nach dem Begriff «FROM»)
erstellt und mit einem Alias versehen. Jetzt ist derPrimärschlüssel aus der Tabelle "Ware" in derAbfrage nicht mehr zwingend erforderlich. Die
Abfrage bleibt auch so editierbar.

Abfragen als Bezugstabellen von Abfragen

42

Abbildung 7: Jetzt soll die Rechnungssumme
noch in der Abfrage erscheinen. Bereits die einfache Abfrage der Rechnugssumme ist nicht editierbar, da hier gruppiert und summiert wird.

Abbildung 8: Mit der zweiten Unterabfrage wird das scheinbar Unmögliche möglich. Die vorhergehenden Abfrage wird als Unterabfrage inder Tabellendefinition dieser Abfrage (nach «FROM») eingefügt. Im
Ergebnis bleibt die gesamte Abfrage so editierbar. Eingaben sind indiesem Fall nur in den Spalten "Anzahl" und "warID" möglich. Dies
wird im Formular anschließend berücksichtigt.
Abfragen als Bezugstabellen von Abfragen

43

Zusammenfassung von Daten mit Abfragen
Sollen Daten in der gesamten Datenbank gesucht werden, so ist dies über die einfachen Formularfunktionen meist nur mit Problemen zu bewältigen. Ein Formular greift schließlich nur auf eine
Tabelle zu, und die Suchfunktion bewegt sich nur durch die Datensätze dieses Formulars.
Einfacher wird der Zugriff auf alle Daten mittels Abfragen, die wirklich alle Datensätze abbilden.
Im Kapitel Beziehungsdefinition in der Abfrage wurde so eine Abfragekonstruktion bereits angedeutet. Diese wird im Folgenden entsprechend der Beispieldatenbank ausgebaut.
SELECT"Medien"."Titel","Untertitel"."Untertitel","Verfasser"."Verfasser"
FROM "Medien"
LEFT JOIN "Untertitel"
ON "Medien"."ID" = "Untertitel"."Medien_ID"
LEFT JOIN "rel_Medien_Verfasser"
ON "Medien"."ID" = "rel_Medien_Verfasser"."Medien_ID"
LEFT JOIN "Verfasser"
ON "rel_Medien_Verfasser"."Verfasser_ID" = "Verfasser"."ID"
Hier werden alle "Titel", "Untertitel" und "Verfasser" zusammen angezeigt.
Die Tabelle "Medien" hat insgesamt 9 "Titel". Zu zwei Titeln existieren insgesamt 8 "Untertitel".
Beide Tabellen zusammen angezeigt ergäben ohne einen LEFT JOIN lediglich 8 Datensätze. Zu
jedem "Untertitel" würde der entsprechende "Titel" gesucht und damit wäre die Abfrage zu Ende.
"Titel" ohne "Untertitel" würden nicht angezeigt.
Jetzt sollen aber alle "Medien" angezeigt werden, auch die ohne "Untertitel". "Medien" steht auf derlinken Seite der Zuweisung, "Untertitel" auf der rechten Seite. Mit einem LEFT JOIN werden alle
"Titel" aus "Medien" angezeigt, aber nur die "Untertitel", zu denen auch ein "Titel" existiert.
"Medien" wird dadurch zu der Tabelle, die entscheidend für alle anzuzeigenden Datensätze wird.
Dies ist bereits aufgrund der Tabellenkonstruktion so vorgesehen (siehe dazu das Kapitel «Tabellen Medienaufnahme»). Da zu 2 der 9 "Titel" "Untertitel" existieren erscheinen in der Abfrage jetzt 9+ 8 – 2 = 15 Datensätze.
Die normale Verbindung von Tabellen erfolgt, nachdem alle Tabellen aufgezählt wurden, nach dem Schlüsselwort WHERE.

HinweisWird mit einem LEFT JOIN oder RIGHT JOIN gearbeitet, so wird die Zuweisung direkt nach den beiden Tabellennamen mit ON definiert. Die Reihenfolge ist
also immer
Tablle1 LEFT JOIN Tabelle2 ON Tabelle1.Feld1 =Tabelle2.Feld1 LEFT JOIN Tabelle3 ON Tabelle2.Feld1 =Tabelle3.Feld1 ...

Zu 2 Titeln der Tabelle "Medien" existiert noch keine Verfassereingabe und kein "Untertitel". Gleichzeitig existieren bei einem "Titel" insgesamt 3 "Verfasser". Würde jetzt die Tabelle Verfasser einfach ohne LEFT JOIN verbunden, so würden die beiden "Medien" ohne "Verfasser" nicht angezeigt. Da aber ein Medium statt einem Verfasser drei Verfasser hat würde die angezeigte Zahl an
Datensätzen bei 15 Datensätzen bleiben.
Erst über die Kette von LEFT JOIN wird die Abfrage angewiesen, weiterhin die Tabelle "Medien"als den Maßstab für alles anzuzeigende zu nehmen. Jetzt erscheinen auch wieder die Datensätze,zu denen weder "Untertitel" noch "Verfasser" existieren, also insgesamt 17 Datensätze.
Durch entsprechende Joins wird also der angezeigte Datenbestand in der Regel größer. Durch diesen großen Datenbestand kann schließlich gesucht werden und neben den Titeln werden auch
Zusammenfassung von Daten mit Abfragen

44Verfasser und Untertitel erfasst. In der Beispieldatenbank können so alle von den Medien abhängigen Tabellen erfasst werden.

Schnellerer Zugriff auf Abfragen durch Tabellenansichten
Ansichten, in der SQL-Sprache «View», sind, besonders bei externen Datenbanken, schneller als
Abfragen, da sie direkt in der Datenbank verankert sind und vom Server nur das Ergebnis präsentiert wird. Abfragen werden hingegen erst einmal zum Server geschickt und dort dann verarbeitet.
Bezieht sich eine neue Abfrage auf eine andere Abfrage, so sieht das in Base in der SQL-Ansicht
so aus, als ob die andere Abfrage eine Tabelle wäre. Wird daraus ein 'View' erstellt, so zeigt sich,dass eigentlich mit Unterabfragen (Subselects) gearbeitet wird. Eine Abfrage 2, die sich auf eine
andere Abfrage 1 bezieht, kann daher nicht über SQL-Kommando direkt ausführen ausgeführt
werden, da nur die grafische Benutzeroberfläche, nicht aber die Datenbank selbst die Abfrage 1
kennt.
Auf Abfragen kann von der Datenbank her nicht direkt zugegriffen werden. Dies gilt auch für den
Zugriff über Makros. Views hingegen können von Makros wie Tabellen angesprochen werden.
Allerdings können in Views keine Datensätze geändert werden. Dies ist dem Komfortbedingungender GUI unter bestimmten Abfragebedingungen vorbehalten.

TippEine Abfrage, die über SQL-Kommando direkt ausführen gestartet wird, hat den
Nachteil, dass sie für die GUI nicht mehr sortiert und gefiltert werden kann. Sie kannalso nur begrenzt genutzt werden.
Ein View hingegen ist für Base handhabbar wie eine normale Tabelle – mit der Ausnahme, dass keine Änderung der Daten möglich ist. Hier stehen also trotz direktem
SQL-Befehl alle Möglichkeiten zur Sortierung und zur Filterung zur Verfügung.

Ansichten sind bei manchen Abfragekonstruktionen eine Lösung, um überhaupt ein Ergebnis zu
erzielen. Wenn z. B. auf das Ergebnis eines Subselects zugegriffen werden soll, so lässt sich diesnur über den Umweg eines Views erledigen. Entsprechende Beispiele im Kapitel «Datenbank-Aufgaben komplett»: «Zeilennummerierung» und «Gruppieren und Zusammenfassen».

Schnellerer Zugriff auf Abfragen durch Tabellenansichten

45