jetzt lerne ich Datenbanken mit Visual Basic .NET Der einfache Einstieg mit ADO.NET, SQL, Jet-Engine und XML PETER MONADJEMI Schnellkurs SQL jetzt lerne ich KAPITEL 3 Die Datenbanksprache SQL steht bei ADO.NET im Mittelpunkt. Mit ihrer Hilfe werden Datensätze abgerufen, gelöscht, aktualisiert und spezielle Informationen, wie die Anzahl der Datensätze, die Summe über einzelne Spalten und vieles mehr, abgerufen. Auch gespeicherte Prozeduren in einer SQL-Server-Datenbank werden in SQL programmiert. Für (angehende) Datenbankprogrammierer sind SQL-Kenntnisse daher so wichtig wie gute Tischmanieren für Anwärter des diplomatischen Corps. In diesem Kapitel erhalten Sie einen Schnellkurs in SQL, der Ihre SQL-Kenntnisse auf den Stand bringt, wie er für die Alltagsaufgaben mit ADO.NET benötigt wird. Die Themen für dieses Kapitel: 쐽 SQL – ein Standard mit Geschichte 쐽 SQL und Microsoft = T-SQL 쐽 SQL trainieren 쐽 Abfragen über SELECT 쐽 Datensätze einfügen mit INSERT 쐽 Datensätze aktualisieren mit UPDATE 쐽 Datensätze löschen mit DELETE 쐽 Abfragen über mehrere Tabellen – die Joins 쐽 SQL-Funktionen 쐽 SQL für etwas Fortgeschrittene: Gruppierungen und Unterabfragen 101 3 Schnellkurs SQL 쐽 Datenbanken und Tabellen anlegen 쐽 Etwas mehr SQL gibt es in Kapitel 6, in dem im Zusammenhang mit gespeicherten Prozeduren und Funktionen die Microsoft SQL-Variante T-SQL vorgestellt wird. 0 1 Dieses Kapitel kann die wichtigen Bereiche aus Platzgründen nur streifen. Eine gründliche Einführung zum Thema SQL finden Sie in dem empfehlenswerten Buch Jetzt lerne ich SQL von Frank Langenau (Markt+Technik), in dem außerdem die populären DBMS MDSE und MySQL gegenübergestellt werden. Der besseren Lesbarkeit wegen werden SQL-Kommandos und -Schlüsselwörter in diesem Kapitel (und weitestgehend im gesamten Buch) in Großbuchstaben dargestellt. Für die Programmierung als auch das Austesten mit SQL-Tools spielt die Groß-/Kleinschreibung aber keine Rolle. 3.1 SQL – ein Standard mit Geschichte offizielle SQL-Standard lautet SQL 92 und stammt, Sie werden es sich schon denken können, aus dem Jahre 1992. Das hat aber nicht viel zu bedeuten, da innerhalb der Microsoft-Welt natürlich Microsoft den Ton angibt und mit T-SQL einen eigenen SQL-Standard geschaffen hat, der sich zu 95.5% an SQL 92 anlehnen dürfte1. Es gibt auch einen Nachfolger von SQL 92 mit dem Namen SQL 99, der SQL 92 eigentlich ersetzen soll. Inwieweit diese Absicht tatsächlich einen Einfluss auf die SQL-Dialekte der bekannten Datenbankhersteller hat, entzieht sich meiner Kenntnis.2 1. Falls Sie bislang auf die Definition gewartet haben: SQL ist offiziell keine Abkürzung mehr (früher stand es einmal für »Structured Query Language«). 2. Ich gehe davon aus, dass die offizielle Entwicklung des SQL-Standards praktisch keine Bedeutung mehr hat und ein eventuell doch noch verabschiedeter Standard keinen Einfluss auf TSQL haben dürfte, das vollkommen unabhängig von einem offiziellen Standard von Microsoft weiterentwickelt wird. Hier gilt das Motto »Der beste Standard ist der, den man jeden Tag benutzen kann«. 102 SQL und Microsoft = T-SQL Wer es ganz genau wissen möchte, dem sei das Standardwerk zu SQL empfohlen: Guide to SQL Standard von Chris Date und Hugh Darwen (Verlag Addison Wesley, ISBN 0201964260). Doch Vorsicht, erwarten Sie keine locker, flockige Einführung im Stile eines »Jetzt lerne ich«-Buches. Das ist »Hardcore-SQL«. 3.2 1 SQL und Microsoft = T-SQL In der Microsoft-Welt spielt SQL eine wichtige Rolle, allerdings in Gestalt von T-SQL (Transact SQL), das sich in einigen Details von SQL 92 unterscheidet. Diese Details betreffen Kleinigkeiten und den Umstand, dass nicht alle Kommandos, die durch SQL 92 definiert werden, in T-SQL enthalten sind. Für die praktische Programmierung hat dies aber keine Auswirkungen, zumal sich nur die wenigsten .NET-Programmierer auch in anderen Welten bewegen dürften. T-SQL unterscheidet sich von SQL vor allem durch den Umstand, dass es viele neue Kommandos und Funktionen umfasst, mit denen sich zum Beispiel kleine Programme (die gespeicherten Prozeduren und Funktionen) programmieren lassen. Anders als SQL, das sich auf seine Kernbereiche beschränkt, ist T-SQL bereits eine richtige kleine Programmiersprache, wobei T-SQL-Programme stets innerhalb der Datenbank ausgeführt werden und zum Beispiel keine Ein- und Ausgaben durchführen (es gibt allerdings über eine Systemprozedur die Möglichkeit, auf COM-Komponenten zuzugreifen). Der »harte Kern« von SQL besteht nur aus wenigen Kommandos: SELECT, INSERT, UDPATE und DELETE und einer Hand voll Funktionen, wie MAX, AVG oder TOP. Ganz so einfach ist SQL dann aber noch nicht, denn es gibt zahlreiche Befehlswörter und spezielle Funktionen, mit denen ein SQL-Kommando angereichert wird. SQL muss daher wie eine Programmiersprache gelernt werden. Es dauert daher eine Weile, bis Sie in der Lage sein werden, die gewünschten Daten aus einer Datenbank abzurufen, und es kann Jahre dauern, bis Sie auch die Feinheiten beherrschen. Geht es lediglich darum, Datensätze nach einfachen Kriterien auszuwählen ist SQL kinderleicht. Sollen jedoch Beziehungen zwischen Tabellen berücksichtigt werden, kann es richtig »kompliziert« werden. Hier eine kleine Kostprobe, die den Unterschied deutlich machen wird. Die folgende Abfrage gibt die Namen aller Angestellten der Northwind-Firma zurück: SELECT LastName FROM Employees Doch wie wäre es, wenn Sie die Summe aller Umsätze sehen möchten, die jeder Angestellte im Jahr 1994 gemacht hat? Das wäre natürlich toll, denn ansonsten müssten Sie relativ viel programmieren. Diese Information steckt natürlich nicht in einer einzigen Tabelle (auch wenn dies denkbar wäre, wäre dies im Allgemeinen kein guter Ansatz), sie ergibt sich vielmehr aus der Kombination verschiedener Tabellen: 103 3 Schnellkurs SQL SELECT Employees.LastName, SUM([Order Details].UnitPrice*[Order Details].Quantity-[Order Details].UnitPrice/100*[Order Details].Discount) AS Umsatz FROM [Order Details], Orders, Employees WHERE [Order Details].OrderID=Orders.OrderID AND Orders.EmployeeID=Employees.EmployeeID GROUP BY Employees.LastName Diese Abfrage ist schon »ein wenig« komplizierter. Der Aufwand, sie zu verstehen, lohnt sich in jedem Fall, denn Sie erspart Ihnen nicht nur mehrere Dutzend Zeilen Visual Basic-Code, sondern dürfte auch deutlich schneller sein als seine Schleife, die eventuell zuerst alle Angestellten durchläuft, zu jedem Angestellten den Umsatz abfragt und diesen aufaddiert. Es lohnt sich daher, SQL gut zu beherrschen, denn es ist der Schlüssel zu den Inhalten einer Datenbank. Tabelle 3.1 gibt einen Überblick über die wichtigsten SQL-Kommandos. Tabelle 3.1: SQL-Kommando Die wichtigsten SQL-Komman- SELECT *FROM <Tabelle> dos im Überblick SELECT Feld1, Feld2 FROM <Tabelle> Bedeutung Gibt alle Felder der angegebenen Tabelle zurück. Gibt nur die angegebenen Felder der angegebenen Tabelle zurück. SELECT * FROM <Tabelle> WHERE Feld1 < Wert Gibt alle Datensätze zurück, die ein auf WHERE folgendes Kriterium erfüllen. SELECT MAX(Feld1) FROM <Tabelle> Gibt den größten Wert der Spalte Feld1 als Wert zurück. UPDATE <Tabelle> SET Feld1=Wert1, Feld2=Wert2 WHERE Feld1=Wert3 Aktualisiert die aufgeführten Felder der Tabelle mit den angegebenen Werten, wobei der zu aktualisierende Datensatz das auf WHERE folgende Kriterium erfüllen muss. INSERT INTO <Tabelle> VALUES(Wert1,Wert2,Wert3) Aktualisiert die Tabelle mit den in Klammern aufgeführten Werten. Diese Variante geht davon aus, dass jedes der Felder mit einem Wert belegt wird. INSERT INTO <Tabelle> (Feld1, Feld3) VALUES(Wert1, Wert3) Aktualisiert die Tabelle mit den in Klammern aufgeführten Werten. Diese Variante geht davon aus, dass nur bestimmte Felder mit einem Wert belegt werden. Identitätsfelder (auch AutoIncrement genannt) werden hier nicht aufgeführt, da ihr Inhalt automatisch von der Datenbank gesetzt wird. DELETE FROM <Tabelle> WHERE Feld1=Wert1 Löscht alle Datensätze aus der Tabelle, die das angegebene Kriterium erfüllen. 3.2.1 Die Jet-Engine spricht auch SQL In einer perfekten Welt gäbe es nur ein SQL, an das sich alle halten würden. Doch aus den verschiedenen Gründen ist das nicht der Fall. Selbst innerhalb 104 SQL trainieren der Microsoft-Welt gibt es verschiedene SQL-Dialekte. Neben T-SQL existiert der SQL-Dialekt, der von der Jet-Engine verwendet wird und der sich ebenfalls eng an SQL 92 anlehnt. Gegenüber T-SQL gibt es ein paar wichtige Unterschiede: 쐽 Für die Platzhalter % und _ (der Unterstrich) werden die Symbole * und ? verwendet. Allerdings sorgt OLE DB dafür, dass auch bei Jet-SQL % und _ verwendet werden können. ADO.NET übernimmt dies natürlich beim verwalteten Provider für OLE DB, so dass es keine Probleme geben sollte. 쐽 Jet-SQL unterstützt die (alten) Visual Basic-Funktionen wie DateDiff, DateValue, Left, Right usw., was eine sehr praktische Angelegenheit ist, da sich SQL-Abfrage beinahe so wie reguläre Visual Basic-Abfragen formulieren lassen. Auch T-SQL umfasst derartige Funktionen (allerdings nicht in dieser Vielfalt), die aber eine etwas andere Syntax besitzen. 쐽 Jet-SQL unterstützt einen eigenen Abfragetyp, den es bei T-SQL nicht gibt. Dafür kennt Jet-SQL keine gespeicherten Prozeduren, Funktionen usw. 쐽 Bei den Datumsformaten gibt es geringfügige Unterschiede bei der Frage, welche verschiedenen Variationen, ein Datum darzustellen, erkannt werden. Die Auflistung macht deutlich, dass die Unterschiede im Allgemeinen zu gering sind, als dass sie sich in der Praxis auswirken könnten. Interessant werden diese Unterschiede auch nur dann, wenn ein Programm beide Datenbanktypen unterstützen soll oder wenn ein Programm von Jet-SQL auf T-SQL »umgestellt« wird. 3.3 SQL trainieren SQL lernt sich am besten durch Ausprobieren vieler kleiner Übungen. Zwar wäre es kein allzu großer Aufwand, jedes SQL-Kommando in eine kleine Konsolenanwendung einzufügen, die das Kommando ausführt und das Ergebnis in der Konsole ausgibt, aber es gibt noch eine bequemere Lösung. Diese besteht aus einem kleinen Programm, in dem Sie das SQL-Kommando nur eintippen und nach Drücken von Í das Ergebnis in einem DataGrid sehen. Einen solchen SQL-Trainer finden Sie an verschiedenen Stellen: 쐽 Auf der Buch-CD in Gestalt des Projekts SQLTrainer.sln im Verzeichnis \Quellen\SQLTrainer. 쐽 In Gestalt des Query Analyzers, eines Zubehörprogramms des SQL Servers, das aber leider nicht bei der MSDE dabei ist. 105 3 Schnellkurs SQL 쐽 In Gestalt von QueryExpress, einem kostenlosen .NET-Programm von Joseph Albahari, das beinahe die perfekte Ergänzung zur MSDE ist und das Sie zum Beispiel zum Ausprobieren der SQL-Kommandos in diesem Kapitel verwenden können. Abb. 3.1: QueryExpress erlaubt das schnelle Ausprobieren von SQL-Kommandos. 3.3.1 QueryExpress als Allround-Werkzeug Manche Tools sind beinahe zu schön, um wahr zu sein. In diese Kategorie fällt QueryExpress von Joseph Albahari. Zu mindestens für alle Leserinnen und Leser, die nur über die MSDE verfügen und nun ein Werkzeug brauchen, mit dem sie die Struktur einer SQL-Server-Datenbank sichtbar machen und SQLKommandos gegen eine Datenbank ausführen können. QueryExpress, bei dem es sich ebenfalls um eine .NET-Anwendung handelt, erledigt beide Aufgaben souverän und ist zudem kostenlos erhältlich. Download und Info unter http://www.albahari.com/queryexpress.html. Die Bedienung von QueryExpress ist sehr einfach (und an das Vorbild Query Analyzer des SQL Server angelehnt). Als Erstes stellen Sie die Verbindung zu einer Datenbank her. Anschließend wird ein SQL-Fenster geöffnet, in dessen linker Hälfte eine Datenbank ausgewählt wird und daraufhin die Tabellen und Felder dieser Datenbank in einer typischen Baumstruktur erscheinen. Die rechte Fensterhälfte ist für die Eingabe beliebiger SQL-Kommandos gegen die ausgewählte Datenbank gedacht. Ein Kommando wird über Í ausgeführt, wobei das Ergebnis in einem Grid (alternativ als Text) in der unteren Hälfte angezeigt wird, zusammen mit der Ausführungszeit in Sekunden. Sie können beliebig viele SQL-Fenster öffnen und den Inhalt eines Fensters als Textdatei mit 106 SQL trainieren der Erweiterung .sql speichern, um es zu einem späteren Zeitpunkt wieder laden zu können. Abb. 3.2: Beim QueryExpress ist am Anfang eine Anmeldung erforderlich. 3.3.2 Wenn alle Stricke reißen – Osql.exe hilft immer Sowohl eine reguläre SQL-Server-Installation als auch die MSDE installieren ein kleines Kommandozeilentool mit dem Namen Osql.exe (bzw. Isql.exe bei einem SQL Server), das im Prinzip eine große Hilfe sein kann, wenn man damit leben kann, dass es keine Benutzeroberfläche, sondern nur eine spartanische Kommandozeile gibt. Die Hauptaufgabe von Osql ist es, über SQLSkripte Datenbanken komplett anzulegen oder Elemente zu vorhandenen Datenbanken hinzuzufügen. Aber auch Abfragen können damit ausgeführt werden, da ein SQL-Skript beliebige T-SQL-Kommandos enthalten kann. Und hat man sich an die schlichte Kommandozeile erst einmal gewöhnt, geht manches für erfahrene Anwender schneller von der Hand als mit Query Analyzer & Co. Das folgende SQL-Skript, das in einer Datei Test.sql enthalten ist, soll mit Hilfe von Osql.exe ausgeführt wird: USE Northwind; SELECT LastName, City FROM Employees; = Beim Aufruf von Osql werden Anmeldung und das Ausführen des SQLSkripts in einem Aufwasch erledigt: osql -S "(local)" -E -i test.sql 107 3 Schnellkurs SQL jetzt lerne ich Achten Sie bei den Schaltern auf die Groß-/Kleinschreibung, -e ist nicht das Gleiche wie –E. Eine Liste der wichtigsten Schalter enthält Tabelle 3.2. In der Regel führen SQL-Skripte keine Abfragen durch, sondern sind dazu da, komplette Datenbanken anzulegen. Die SQL-Server-Version der Northwind-Datenbank erhalten Sie auf der Microsoft-Webseite lediglich in Gestalt einer kleinen SQL-Skriptdatei. Wenn Sie diese Datei mit Osql.exe ausführen, wird die komplette Datenbank auf dem ausgewählten Server angelegt. Rufen Sie Osql ohne weitere Schalter außer denen, die für die Anmeldung erforderlich sind, auf, gelangen Sie in den Editormodus. Hier können Sie ein SQL-Skript Zeile für Zeile zusammensetzen und es am Ende mit einem GO ausführen. Möchten Sie ein SQL-Kommando ausführen, aber mit Osql weiterarbeiten, um eventuell weitere SQL-Kommandos auszuführen, geben Sie einfach GO ein. Ein EXIT oder QUIT beendet den Editor wieder. Ein RESET macht alle bisher eingegebenen Zeilen ungültig, und wenn Sie den Editor scheinbar gar nicht mehr verlassen können, drücken Sie Ÿ+C. Tabelle 3.2: Schalter Die wichtigsten Schalter von -S Osql.exe -d 108 Bedeutung Gibt den Servernamen an. Gibt den Datenbanknamen an (entspricht dem USE-Kommando). -L Listet alle registrierten Server auf. -i Auf diesen Schalter folgt der Name der SQL-Skriptdatei. -? Listet die Schalter auf. -U Benutzername für Login. -H Hostname für Login. -l Legt Login-Timeout fest. -c Ende des Kommandos. -Q Abfrage ausführen und wieder beenden. -o Auf diesen Schalter folgt der Name einer Datei, in welche die Ausgabe eingetragen wird. -P Kennwort für Login. -E Verbindung wird ohne Login mit integrierter Windows-Sicherheit durchgeführt. -w Legt die Breite einer Spalte fest. -q Führt das folgende SQL-Kommando aus, das in Anführungsstriche gesetzt wird. Mehrere Kommandos werden durch ein Semikolon getrennt. Abfragen über SELECT 3.4 jetzt lerne ich Abfragen über SELECT Das SELECT-Kommando ist das mit Abstand wichtigste SQL-Kommando. Es gibt einen oder mehrere Datensätze aus einer oder mehreren Tabellen zurück, wobei über die WHERE-Klausel eines oder mehrere Filterkriterien angegeben werden können.1 Das folgende Kommando gibt alle Datensätze der Tabelle Employees zurück: SELECT * From Employees = Ein SELECT-Kommando wird entweder über die ExecuteReader-Methode des OleDbCommand-Objekts (bzw. SqlCommand) oder über ein OleDbDataAdapter-Objekt (bzw. SqlDataAdapter) ausgeführt. Möchte man die Anzahl der Datensätze erfahren, geschieht dies am einfachsten über die Count-Eigenschaft der Rows-Auflistung des DataTable-Objekts. Bei einem DataReader muss erst die komplette Datensatzgruppe in einer Schleife durchlaufen werden. Hier ist es oft einfacher, zuerst die SQL-Funktion COUNT mit der ExecuteScalar-Methode auszuführen – mehr dazu in Kapitel 3.9. Beim Microsoft SQL Server können mehrere SELECT-Kommandos zusammengefasst (Batch-Ausführung) und die Ergebnissets einem SqlDataReader zugewiesen werden. Über die NextResult-Methode wird auf das nächste Ergebnisset umgeschaltet, ohne dass erneut eine Datenbankabfrage durchgeführt wird. 3.5 0 Datensätze einfügen mit INSERT Das INSERT INTO-Kommando fügt einen oder mehrere Datensätze in eine Tabelle ein. Dabei kommt es darauf an, dass Einschränkungen (in der Regel Primärschlüsseleinschränkungen) nicht verletzt werden. Mit anderen Worten, es kann zum Beispiel kein Datensatz eingefügt werden, dessen Wert für ein Primärschlüsselfeld dazu führen würde, dass der Wert doppelt vorkommt (Primärschlüssel müssen stets eindeutig sein). 1. Wie im richtigen Leben dient auch bei SQL eine Klausel dazu, eine getroffene Absprache einzuschränken oder genauer zu definieren. 109 3 Schnellkurs SQL jetzt lerne ich = Das folgende Kommando fügt einen neuen Datensatz in die Tabelle Employees ein. INSERT INTO Employees (LastName, FirstName, Hiredate) VALUES ('Monadjemi', 'Peter','1.4.2004' Das Feld EmployeeID wird nicht aufgeführt, da es ein AutoIncrement-Feld (beim SQL Server auch Identitätsfeld genannt) ist, das von der Datenbank einen fortlaufenden Wert erhält. 1 0 Beim Microsoft SQL Server kann ein Identitätsfeld über die T-SQL-Variable @@Identity angesprochen werden. Soll eine Einfügeoperation in einer SQL Sever-Datenbank den aktuellen Wert der Identitätsspalte, die in der Regel den Primärschlüssel der Tabelle darstellt, zurückgeben, geschieht dies am einfachsten über eine gespeicherte Prozedur, die den @@Identity-Wert als Parameter zurückgibt. 3.6 Datensätze aktualisieren mit UPDATE Das UPDATE-Kommando aktualisiert einen oder mehrere Felder in einen oder mehrere Datensätze in einer Tabelle (es kann pro Kommando immer nur eine Tabelle aktualisiert werden). Der Wert wird einem Feld über das SET-Schlüsselwort zugewiesen, wobei mehrere Felder durch Kommata getrennt werden. Welche Datensätze aktualisiert werden, wird über die WHERE-Klausel festgelegt. = Das folgende SQL-Kommando senkt die Preise aller Produkte der Tabelle Products, die mit Discontinued=1 als Auslaufprodukte gekennzeichnet sind, um 10%. UPDATE Products SET UnitPrice = UnitPrice * 0.9 WHERE Discontinued=1 Wird dieses Kommando mit ExecuteNonQuery ausgeführt, erhält man von der Methode die Anzahl der geänderten Datensätze zurück. Sollen mehrere Felder pro Datensatz aktualisiert werden, werden diese im UPDATE-Kommando durch Kommata getrennt zusammengefasst: UPDATE Products SET UnitPrice = UnitPrice * 0.9, ReorderLevel = 0 WHERE Discontinued=1 110 Datensätze löschen mit DELETE 3.7 jetzt lerne ich Datensätze löschen mit DELETE Das DELETE-Kommando löscht einen oder mehrere Datensätze aus einer Tabelle. Sollen nicht alle Datensätze gelöscht werden, muss über die WHERE-Klausel ein Kriterium angegeben werden. Das folgende SQL-Kommando löscht aus der Tabelle Employees alle Datensätze mit einer EmployeeID größer 9: DELETE FROM Employees WHERE EmployeeID>9 = Wird dieses Kommando mit ExecuteNonQuery ausgeführt, erhält man von der Methode die Anzahl der gelöschten Datensätze zurück. Speziell beim Microsoft SQL Server als auch beim Oracle SQL Server gilt, dass umfangreichere Einfüge-, Lösch- oder Aktualisierungsaktionen aus Performancegründen besser über gespeicherte Prozeduren ausgeführt werden. Mehr dazu in Kapitel 6. 3.8 0 Abfragen über mehrere Tabellen – die Joins Bei einer JOIN-Operation werden die Datensätze aus zwei oder mehr Tabellen verknüpft, also zu einer virtuellen Tabelle zusammengefasst. In der Regel wird dabei ein Kriterium bestehend aus Feldern, welche die zu verknüpfenden Tabellen gemeinsam haben, verwendet, damit nur bestimmte Felder in die Ergebnismenge übernommen werden. Das klassische Beispiel für eine JOINOperation liegt vor, wenn alle Datensätze in einer Master-Details-Beziehung zusammengefasst werden sollen. Eine solche Beziehung liegt in der Beispieldatenbank Northwind zwischen den Tabellen Orders (Master) und Order Details (Details) oder Customers (Master) und Orders (Details) vor. Warum? Nun, weil zu jedem Auftrag eine bestimmte Anzahl an Bestelldetails und zu jedem Kunden eine bestimmte Anzahl an Aufträgen gehören. Man spricht auch von einer 1:n-Beziehung. Möchte man feststellen, welche Bestellungen für ein Produkt vorliegen, geht dies am einfachsten über eine Join-Operation: SELECT Products.ProductID, ProductName, OrderID FROM Products, [Order Details] WHERE Products.ProductID = [Order Details].ProductID ORDER BY Products.ProductID = 111 3 Schnellkurs SQL jetzt lerne ich In diesem Fall wird eine vereinfachte SQL-Syntax verwendet, das heißt, auf das offizielle JOIN-Befehlswort wird verzichtet, zumal dieses beim Oracle SQL Server nicht unterstützt wird. Voll ausgeschrieben lautet das obige Kommando wie folgt: SELECT Products.ProductID, ProductName, OrderID FROM Products INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID ORDER BY Products.ProductID Hier liegt ein sog. Inner Join vor, bei dem jedem Datensatz der Master-Tabelle eine bestimmte Anzahl an Datensätzen der Details-Tabelle zugeordnet wird. Pro vorhandener Beziehung, die über das gemeinsame Feld ProductID hergestellt wird (das in beiden Tabellen durchaus unterschiedliche Namen tragen kann), wird ein neuer Datensatz in einer virtuellen Tabelle angelegt, der alle Felder aus beiden Datensätzen enthält. 1 0 Kommen in beiden Tabellen Felder mit gleichen Namen vor, muss dem Feldnamen der Tabellenname vorangestellt werden. Aus ProductID wird so Products.ProductID. Kommen in einem SQL-Kommando relativ viele Felder vor, denen der Tabellenname vorangestellt werden muss, kann es eine kleine Abkürzung sein, über AS einen Aliasnamen für die Tabelle zu verwenden. Das folgende SQLKommando funktioniert nur beim Microsoft SQL Server (T-SQL): SELECT P.ProductID, ProductName, OrderID FROM Products AS P INNER JOIN [Order Details] ON P.ProductID = [Order Details].ProductID ORDER BY P.ProductID 1 ADO.NET erlaubt keine Aktualisierungen bei DataTables, die aus mehreren Tabellen entstanden sind. Dies ist eine Einschränkung von Join-Operationen, welche die Programmierung deutlich aufwändiger macht, als sie sein könnte. 3.9 SQL-Funktionen SQL stellt eine Reihe von Funktionen zur Verfügung, die, da sie die Felder in mehreren Datensätze zusammenfassen, als Aggregatfunktionen bezeichnet werden. Stellvertretend werden im Folgenden die häufig benutzten Aggregatfunktionen COUNT, MAX und AVG vorgestellt. Tabelle 3.3 stellt die wichtigsten SQL-Funktionen zusammen. 112 SQL für etwas Fortgeschrittene: Gruppierungen und Unterabfragen jetzt lerne ich SQL-Aggregatfunktionen werden über die ExecuteScalar-Methode des Command-Objekts ausgeführt. Funktion Bedeutung AVG Berechnet den Durchschnitt über alle Werte einer Spalte. COUNT Zählt die Anzahl an Datensätzen. LEFT Gibt die ersten n Zeichen vom Anfang einer Zeichenkette zurück. LEN Gibt die Länge einer Zeichenkette zurück. MAX Gibt den größten Wert einer Spalte zurück. MIN Gibt den kleinsten Wert einer Spalte zurück. POWER Potenziert einen Ausdruck um den angegebenen Faktor. RIGHT Gibt die ersten n Zeichen vom Ende einer Zeichenkette zurück. STDEV Berechnet die Standardabweichung der Werte einer Spalte. VAR Berechnet die Variante der Werte einer Spalte. Die COUNT-Funktion zählt einfach nur die Anzahl an Datensätzen, die ein bestimmtes Kriterium erfüllen. SELECT COUNT(*) FROM Products WHERE Discontinued=1 Tabelle 3.3: Wichtige SQLFunktionen beim Microsoft SQL Server 2000 = Die MAX-Funktion gibt den größten Wert in einer Spalte von nummerischen Werten zurück: SELECT Max(EmployeeID) FROM Employees Die AVG-Funktion berechnet den Durchschnitt in einer Spalte von nummerischen Werten. Die folgende Abfrage gibt den Durchschnittspreis aller an einem bestimmten Datum verkauften Artikel zurück: SELECT AVG(UnitPrice) FROM Orders, [Order Details] WHERE Orders.OrderID=[Order Details].OrderID AND OrderDate='9.9.1996' 3.10 SQL für etwas Fortgeschrittene: Gruppierungen und Unterabfragen Bislang war SQL relativ einfach, auch wenn bereits etwas Übung und Erfahrung dazu gehört, ein UPDATE-Kommando aus dem Kopf formulieren zu können (wie Sie in Kapitel 4 lernen werden, ist es sehr viel praktischer, für alle variablen Werte Platzhalter zu übergeben, anstatt den SQL-String einzeln zusammenzubauen). SQL kann jedoch noch sehr viel mehr, was im Folgenden mit den Gruppierungen und Unterabfragen nur angedeutet werden. 113 jetzt lerne ich 3 Schnellkurs SQL 3.10.1 Gruppierungen mit der Group By-Klausel Ein wichtiger Aspekt bei SQL sind Gruppierungen über die GROUP BY-Klausel und gegebenenfalls das HAVING-Prädikat. = Die folgende Abfrage gibt die Anzahl der verkauften Produkte pro Kategorie zurück: SELECT COUNT(*) AS Anzahl, CategoryName FROM Categories, Products, [Order Details] WHERE Products.ProductID=[Order Details].ProductID AND Categories.CategoryID = Products.CategoryID GROUP BY CategoryName Dass diese Abfrage etwas umfangreicher ist, hat nur indirekt etwas mit der GROUP BY-Klausel zu tun, sondern mit dem Umstand, dass Gruppierungen nur dann einen echten Vorteil bringen, wenn sie im Rahmen einer etwas umfangreicheren Abfrage eingesetzt werden. Gruppierungen können auch sehr einfach sein, wie das folgende Beispiel belegt, das die Produkte nach Kategorien gruppiert und die Anzahl der Produkte pro Kategorie zurückgibt: SELECT Count(*) AS Anzahl, CategoryID FROM Products GROUP BY CategoryID Abb. 3.3: QueryExpress zeigt das Resultat der GROUP BY-Abfrage an. 114 SQL für etwas Fortgeschrittene: Gruppierungen und Unterabfragen 1 Die folgende Abfrage gibt die Anzahl aller Produkte mit ihrer ProductID zurück, die mit einem Rabatt verkauft wurden: SELECT Count(ProductID) AS Anzahl, ProductID FROM [Order Details] Where Discount > 0 GROUP BY ProductID ORDER BY ProductID jetzt lerne ich = Der nächste Schritt könnte darin bestehen herauszufinden, wie viel »Verlust« das Geschäft mit der Rabattierung gemacht hat. Auch das ist per SQL relativ einfach möglich: SELECT SUM(UnitPrice*Quantity) - SUM((UnitPrice*1Discount)*Quantity) AS RabattDiff FROM [Order Details] WHERE Discount > 0 Diese Abfrage gibt am Ende einen Wert zurück (bei ADO.NET würde sie daher über die ExecuteScalar-Methode eines Command-Objekts ausgeführt werden), der für die Differenz der Summen der verkauften Produkte und der verkauften Produkte inklusive Rabatt steht. Die folgende Abfrage gibt an, wie oft die einzelnen Produkte rabattiert verkauft wurden: SELECT COUNT(ProductName) AS Anzahl, ProductName FROM Products, [Order Details] WHERE [Order Details].Discount>0 AND Products.ProductID = [Order Details].ProductID GROUP BY ProductName ORDER BY Anzahl DESC Und bei welchem Produkt hat die Firma den meisten Verlust bezogen auf die Rabattierung gemacht? Bevor es richtig kompliziert wird, verrät Ihnen der Autor einen kleinen »Trick«, der SQL-Programmierern oft aus der Patsche hilft: das TOP-Prädikat, das stets die obersten n Datensätze zurückgibt. Indem die Abfrage also nach der Differenz zwischen Verkaufspreis und Rabattpreis absteigend sortiert und nur den ersten Datensatz zurückgibt, erhalten Sie den Datensatz mit dem größten Verlust: SELECT TOP 1 SUM(UnitPrice*Quantity) AS Betrag, SUM ((UnitPrice*1Discount)*Quantity) AS Rabatt, SUM(UnitPrice*Quantity) – SUM (UnitPrice*1-Discount*Quantity) AS RabattDiff, ProductID FROM [Order Details] WHERE Discount > 0 GROUP BY ProductID Order BY RabattDiff DESC Das Beispiel zeigt sehr schön, wie ein cleveres SQL-Kommando die Programmierung vereinfachen kann. Natürlich gibt es aber auch Situationen, an denen selbst SQL an seine Grenzen stößt. Entweder weil das SQL-Kommando so kompliziert werden würde, dass es »kein Mensch mehr versteht«1, oder die Abfrage gar nicht möglich ist. Hier kommen die gespeicherten Prozeduren oder Funktionen ins Spiel (Kapitel 6), mit denen sich mehrere SQLKommandos zusammenfassen. 1. Bekanntlich verbringen Entwickler in der Industrie 47% ihrer Zeit damit, sich in den Programmcode einzuarbeiten, den andere »verbrochen« haben. 115 jetzt lerne ich 3 Schnellkurs SQL Das Ergebnis der ersten Abfrage als Variable kann in einer folgenden Abfrage enthalten sein oder doch wieder die gute, alte Visual Basic-Programmierung. Abb. 3.4: Alles andere als trivial – diese Abfrage gibt das Produkt zurück, für das es den größten Rabattbetrag gibt. Eine (lästige) Einschränkung und eine echte Hürde auf dem Weg zum SQLExperten ist der Umstand, dass auf SELECT neben einer Aggregatfunktion nur Felder folgen dürfen, die über GROUP BY aufgeführt werden. Möchte man daher in dem obigen Beispiel auch die Kategorienamen erhalten, muss eine Unterabfrage zum Einsatz kommen. 3.11 Unterabfragen SQL-Abfragen können verschachtelt werden, das heißt auf die WHERE-Klausel können weitere Abfragen folgen, deren Ergebnis zum Beispiel als Einschränkungskriterium verwendet wird. Diese Unterabfragen (engl. »Subqueries«) gehören bereits zu den etwas anspruchsvolleren Themen bei SQL. Sie werden zwar nur relativ selten benötigt, doch wer sie beherrscht, kann sich viel Programmierarbeit sparen. Bezüglich ADO.NET gibt es keine Besonderheiten zu beachten, da sie exakt wie eine einfache SELECT-Abfrage ausgeführt werden. = 116 Das folgende Beispiel gibt alle Produkte aus, deren Preis größer als der Durchschnittspreis aller Produkte ist: SELECT ProductName, UnitPrice FROM Products WHERE UnitPrice > (SELECT AVG(UnitPrice) FROM Products) ORDER BY UnitPrice Datenbanken und Tabellen anlegen jetzt lerne ich Das folgende Beispiel gibt zusätzlich auch die Anzahl an Bestellungen dieser Produkte zurück: SELECT COUNT(OrderID), OrderID FROM Products, [Order Details] WHERE Products.UnitPrice > (SELECT AVG(UnitPrice) FROM Products) AND Products.ProductID = [Order Details].ProductID GROUP BY OrderID ORDER BY OrderID DESC Häufig lässt sich eine kompliziert wirkende Unterabfrage durch eine deutlich einfachere Join-Verknüpfung ersetzen. Unterabfragen in eine Abfrage einbauen Eine komplette Unterabfrage kann als Feldname in eine SELECT-Abfrage eingebaut werden, so dass das Ergebnis der Unterabfrage in die von der Abfrage zurückgegebenen Felder aufgenommen wird. Das folgende Beispiel gibt die Namen aller Kunden mit der Anzahl ihrer Bestellungen sortiert nach dieser Anzahl zurück. SELECT CompanyName, CustomerID, (SELECT Count(*) FROM Orders WHERE Orders.CustomerID=Customers.CustomerID) AS [Anzahl Aufträge] FROM Customers ORDER BY [Anzahl Aufträge] = Spätestens an dieser Stelle wird deutlich, dass sich mit SQL einiges anstellen lässt und profunde SQL-Kenntnisse beinahe genauso wichtig sind wie gute Programmierkenntnisse. Trotz aller Veränderungen in den letzten Jahren und Jahrzehnten hat SQL nichts an Bedeutung verloren. Im Gegenteil, mit ADO.NET rückt die (offiziell 1986 standardisierte) Datenbankabfrage erneut in den Mittelpunkt. 3.12 Datenbanken und Tabellen anlegen SQL kann auch das Anlegen von Datenbanken, Tabellen und anderen Inhalten, wie gespeicherte Prozeduren, übernehmen. Auch wenn dafür meistens ein komfortables Programm wie Microsoft Access (ab Version 2000) oder der Enterprise Manager des SQL Servers besser geeignet ist, wenn es sein muss, geht es auch programmgesteuert, indem die SQL-Kommandos über ein SqlCommand-Objekt und dessen ExecuteNonQuery-Methode der Reihe nach ausgeführt werden. Es gibt sogar einen wichtigen Vorteil. Dieser besteht darin, dass das Anlegen jederzeit auf Knopfdruck wiederholt werden kann. Muss ein Programm die benötigte Datenbank erst anlegen, ist dies, neben einem SQLSkript, sogar die einzige mögliche Variante. 117 jetzt lerne ich 3 Schnellkurs SQL 3.12.1 Das CREATE-Kommando Das universelle CREATE-Kommando ist für praktisch alles zuständig, was innerhalb einer SQL-Server-Datenbank angelegt werden kann: Tabellen, Indices, Einschränkungen, Trigger, gespeicherte Prozeduren und sogar Datenbanken. = Das folgende Kommando legt eine neue Datenbank für den lokalen SQL Server an. CREATE DATABASE TestDB Auch wenn dieses Kommando im Datenbankalltag mit zusätzlichen Parametern, etwa einer Mindestgröße für die Datenbank, aufgerufen wird, reicht diese Variante vollkommen aus. Die soeben frisch angelegte Datenbank besitzt noch keine Tabellen. Das kann ebenfalls das CREATE-Kommando erledigen, nur dass es anstelle von CREATE DATABASE nun CREATE TABLE heißen muss und zusätzlich zum Tabellennamen auch alle Felder der Tabelle sowie gegebenenfalls auch Einschränkungen aufgeführt werden. = Das folgende Beispiel fügt zur aktuellen Datenbank eine Tabelle mit dem Namen »Autoren« hinzu, die über die Felder AutorID und AutorName verfügt und bei der das Feld AutorID mit einem Primärschlüssel versehen wird. Außerdem darf AutorID keine Nullwerte erhalten, das Feld AutorName dagegen schon. CREATE TABLE Autoren (AutorID int NOT NULL CONSTRAINT pkAuID PRIMARY KEY, AutorName varchar(64) NULL ) Abb. 3.5: Auch das Anlegen von Tabellen ist in Query Express problemlos möglich. 118 Datenbanken und Tabellen anlegen Auch diese »Sorte« von SQL-Kommandos können Sie mit dem Query Analyzer aus einer SQL Server 2000-Installation oder QueryExpress (siehe Kapitel 3.3.1) ausführen. 3.12.2 jetzt lerne ich 1 Die Kommandos ALTER und DROP Für Datenbanken und deren Elemente, die bereits existieren und nun geändert werden sollen, gibt es das ALTER-Kommando, das einfach anstelle von CREATE eingesetzt wird. Das folgende SQL-Kommando ändert den Namen einer vorhandenen Datenbank: ALTER DATABASE TESTDB MODIFY NAME = TESTDBNEU = Regelrecht brisant ist das DROP-Kommando, denn es entfernt ein Datenbankelement oder die Datenbank selber ohne viel Aufhebens. Das folgende SQL-Kommando löscht die Datenbank TestDBNeu. DROP DATABASE TestDBNeu Das war’s – weg ist die Datenbank samt ihrem Inhalt. Führen Sie daher dieses Kommando nie einfach nur zum Spaß aus oder weil Sie neugierig sind, ob wirklich kein Warnhinweis erscheint (es erscheint keiner). Natürlich müssen Sie beim SQL Server mit einem Benutzerkonto angemeldet sein, das die erforderlichen Berechtigungen besitzt, und das obige Kommando kann nur ausgeführt werden, wenn eine andere Datenbank als die zu löschende Datenbank die aktive Datenbank ist. Aber es zeigt sehr eindrucksvoll, wie mächtig SQL beim SQL Server ist. 3.12.3 = Die Datentypen des SQL Servers Der SQL Server arbeitet mit einem eigenen und sehr umfangreichen Satz an Datentypen, die in Tabelle 3.4 aufgeführt sind. Die Datentypen sind (natürlich) nicht mit jenen von Visual Basic.NET identisch, wenngleich es gewisse Übereinstimmungen gibt. Die rechte Spalte enthält daher meistens einen Datentypen in Visual Basic.NET, der »in etwa« passen könnte. Ein Strich bedeutet, dass es ein vergleichbares Pendant gibt. 119 3 Schnellkurs SQL jetzt lerne ich 0 Die SQL-Server-Datentypen werden in der .NET-Klassenbibliothek über die Enumeration SqlDbType im Namespace System.Data.SqlTypes zur Verfügung gestellt. Das ist sehr praktisch, wenn Sie beim Aufruf einer gespeicherten Prozedur (siehe Kapitel 6) den richtigen Parameter auswählen möchten. Parallel gibt es die Enumeration SqlTypes im gleichen Namespace. Sie enthält die Namen der SQL-Server-Datentypen, dieses Mal aber angepasst an die zur Auswahl stehenden Datentypen im .NET Framework. Anstelle von Binary heißt es SqlBinary, anstelle von Float heißt es SqlDouble. Mit anderen Worten, diese Auflistung nimmt bereits die Zuordnung zwischen SQLServer- und .NET-Datentyp vor und erleichtert die Auswahl des richtigen Typs. 1 Tabelle 3.4: Die Datentypen des SQL Servers und ihre Pendants (sofern vorhanden) bei Visual Basic.NET in der Übersicht 120 Mit SQL Server 2005 wird es eine sehr viel engere Übereinstimmung zwischen den Datentypen des SQL Servers und denen, die bei .NET durch das CTS (Common Type System) vorgegeben sind. Datentyp Bedeutung CTS-Pendant bei SQL-Types Visual Basic.NET Bigint Große 64-Bit-Ganzzahl im Bereich –2^63 bis 2^63 –1. Long SqlInt64 Int 32-Bit-Ganzzahl im Bereich –2^32 bis 2^32 –1. Integer SqlInt32 Smallint 16-Bit-Ganzzahl im Bereich –32.678 bis +32.767 Short SqlInt16 Tinyint Kleine 8-Bit-Ganzzahl im Bereich 0 bis 255. Byte SqlByte Bit Ganzzahl, die nur die Werte 0 und 1 annehmen kann. Byte bzw. Boolean - Decimal Feste Nachkommazahl im Bereich –10^38 bis +10^38 –1. Decimal SqlDecimal Numeric Entspricht decimal. - SqlDecimal Money - (Decimal) Feste Nachkommazahl im Bereich –2^63 bis +2^63–1, die aufgrund einer festen Genauigkeit von fünf Nachkommastellen speziell für Geldbeträge geeignet ist. SqlMoney Datenbanken und Tabellen anlegen Datentyp Bedeutung CTS-Pendant bei SQL-Types Visual Basic.NET Smallmoney Wie money, nur dass der Wertebereich zwischen –214,748.3648 und +214,748.3647 liegt. - (Decimal) SqlMoney Float Doppelt genaue Fließkommazahl mit bis zu 15 Nachkommastellen. Double SqlDouble Real Einfach genaue Fließkommazahl mit bis zu sieben Nachkommastellen. Single SqlSingle DateTime Datumstyp Date SqlDateTime - (Date) SqlDateTime Smalldatetime Datumstyp mit einem deutlich jetzt lerne ich Tabelle 3.4: Die Datentypen des SQL Servers und ihre Pendants (sofern vorhanden) bei Visual Basic.NET in der Übersicht (Forts.) kleineren Datumsbereich als Wertebereich und einer Genauigkeit von nur einer Minute. Char ANSI-Zeichenkette fester Länge, - (String) die bis zu 8.000 Zeichen umfassen kann. SqlString Varchar - (String) ANSI-Zeichenkette variabler Länge, die bis zu 8.000 Zeichen umfassen kann. SqlString Text ANSI-Zeichenkette variabler Länge, die bis zu 2 Milliarden Zeichen umfassen kann. SqlString Nchar - (String) Unicode-Zeichenkette fester Länge, die bis zu 4.000 Zeichen umfassen kann SqlString Nvarchar Unicode-Zeichenkette variabler - (String) Länge, die bis zu 4.000 Zeichen umfassen kann. SqlString Ntext Unicode-Zeichenkette variabler Länge, die bis zu 1 Milliarden Zeichen umfassen kann. SqlString Binary Binäres Feld fester Länge, das bis zu 8.000 Bytes groß werden kann. SqlBinary Varbinary Binäres Feld variabler Länge, das bis zu 8.000 Bytes groß werden kann. - SqlBinary Image Binäres Feld variabler Länge, das bis zu 2 Milliarden Bytes groß werden kann. - SqlBinary String String 121 jetzt lerne ich 3 Schnellkurs SQL 3.12.4 Die Rolle der Einschränkungen Jede Tabelle kann mit einer oder mehreren Einschränkungen (engl. »Constraints«) versehen werden, die sich auf einzelne Felder der Tabelle beziehen. Einschränkungen sollen die Integrität einer Datenbank sicherstellen und sind die Grundlagen für Beziehungen zwischen zwei Tabellen, die in der Datenbank gespeichert werden und zum Beispiel dafür sorgen, dass, wenn ein Datensatz aus einer »Elterntabelle« mit einem Primärschlüssel gelöscht wird, automatisch (ohne, dass dafür ein so genannter Trigger für die Tabelle definiert werden muss) alle Datensätze aus einer dazu in Beziehung stehenden »Kindtabelle« gelöscht werden, die den Wert des Primärschlüsselfeldes in ihrem Fremdschlüsselfeld enthalten. Die bekannteste Einschränkung ist die Primärschlüsseleinschränkung, die einem Feld auferlegt, dass es bezogen auf die Spalte nur eindeutige Werte besitzen darf. Beim SQL Server 2000 werden folgende Einschränkungen unterschieden: 쐽 Primary Key 쐽 Unique 쐽 Foreign Key 쐽 Check 쐽 Not Null Die Primary Key-Einschränkung bewirkt, dass das Feld (oder die Felder) einen eindeutigen Wert innerhalb der Spalte besitzen müssen. Jede Tabelle sollte einen Primärschlüssel besitzen, wenngleich dies nicht obligatorisch ist. Über den Primärschlüssel wird erreicht, dass jeder Datensatz innerhalb der Tabelle unterscheidbar ist. Die Unique-Einschränkung bewirkt ebenfalls, dass der Feldwert innerhalb der Spalte eindeutig sein muss, nur dass das Feld nicht zum Primärschlüssel gehören muss. Die Foreign Key-Einschränkung (Fremdschlüsseleinschränkung) verhindert jede Aktion, die eine Verbindung zwischen zwei zueinander in einer Beziehung stehenden Tabellen zerstören würde. Ein Fremdschlüssel ist ein Feld in einer Tabelle, das den gleichen Wert besitzt wie ein anderes Feld in einer anderen Tabelle, das dort ein Primärschlüssel ist. Über die Foreign Key-Einschränkung wird die so genannte referentielle Integrität der Datenbank gewährleistet. Dieser kompliziert klingende Begriff hat eine recht einfache Bedeutung, die in diesem Buch an verschiedenen Stellen erklärt wird. Hier noch einmal die Kurzform: Würde aus der Northwind-Datenbank ein Datensatz aus der Tabelle Customers gelöscht werden, gäbe es in der Orders-Tabelle eine Reihe von Datensätzen dieses Kunden, zu denen nun kein passender Datensatz in der Customers-Tabelle mehr gehört. Die referentielle Integrität in der Datenbank wäre damit zerstört, und manche Abfragen wür- 122 Datenbanken und Tabellen anlegen jetzt lerne ich den nicht mehr funktionieren. Damit dies nicht passiert, müssen beim Datenbankentwurf Fremdschlüsseleinschränkungen gesetzt werden. Die Check-Einschränkung begrenzt den Wert, den eine Spalte annehmen kann. Die Not Null-Einschränkung stellt sicher, dass keine Spalte einen Null-Wert besitzen kann. Das folgende SQL-Kommando legt eine Tabelle mit dem Namen Buecher an, in der für das Feld AutorID eine Fremdschlüsselbeziehung mit dem gleichnamigen Feld in der Tabelle Autoren eingerichtet wird. = CREATE TABLE Buecher (BuchID int NOT NULL CONSTRAINT pkBuchID PRIMARY KEY, AutorID int NOT NULL CONSTRAINT AUTOR_BUCH FOREIGN KEY (AutorID) REFERENCES Autoren(AutorID), Titel varchar(128) NULL ) Weitere Beispiele für SQL-Kommandos finden Sie in Kapitel 6, in dem über das CREATE-Kommando eine gespeicherte Prozedur in der Datenbank angelegt wird. Ab SQL Server 2000 können auf das REFERENCES-Schlüsselwort in einer Fremdschlüsseleinschränkung ein ON DELETE CASCADE und ein ON DELETE UPDATE folgen, mit der eine Lösch- und Aktualisierungsverfolgung bereits auf der Ebene der Datenbank implementiert wird. Das erspart die Programmierung eines Triggers, der ansonsten immer dann aktiv werden müsste, wenn ein Datensatz in einer Tabelle mit einem Primärschlüssel gelöscht oder aktualisiert wird. 3.12.5 1 Eine Referenz zu T-SQL T-SQL ist ein umfassender SQL-Dialekt mit vielen Kommandos, Funktionen und Spezialitäten. Hinzu kommen Hunderte von gespeicherten Prozeduren, die in der Systemdatenbank einer SQL-Server-Installation enthalten sind und die den Umfang von T-SQL enorm erweitern. Ist das denn irgendwo beschrieben, gibt es eine »Liste aller Befehle«? Die gibt es selbstverständlich. Zum einen umfasst eine SQL-Server-Installation eine umfangreiche Hilfe (auch »SQL Server Books Online« genannt), die sämtliche Kommandos, Funktionen, Operatoren und gespeicherte Prozeduren mit Beispielen enthält. Sie werden es sich schon denken können, bei der MSDE ist diese Hilfe leider nicht dabei. Doch das ist kein Grund zu verzagen, denn die komplette Dokumentation zum SQL Server 2000 gibt es (allerdings nur auf Englisch) auch im Internet unter: http://msdn.microsoft.com/library/en-us/tsqlref/ts_tsqlcon_6lyk.asp 123 jetzt lerne ich 3 Schnellkurs SQL Hier können Sie alles zu T-SQL nachschlagen. Sehr viel besser sind natürlich die SQL Server Books Online, da Sie diese etwas schneller durchsuchen können. 0 Netterweise stellt Microsoft auch die aktuelle Version der SQL Server Books Online für den SQL Server 2000 (als auch für den Vorgänger 7.0) zum Download zur Verfügung. Die Adresse lautet: http://www.microsoft.com/sql/techinfo/productdoc/2000/books.asp Nach der Installation erhalten Sie eine Chm-Datei, die alle Texte enthält. Abb. 3.6: Sehr nett – die SQL-ServerDokumentation sowohl für die Version 7.0 als auch 2000 gibt es als kostenlosen Download bei Microsoft. 3.13 Zusammenfassung SQL-Kenntnisse sind für ADO.NET Pflicht. Das hat aus zwei Gründen seine Vorteile: 1. SQL ist ein anerkannter und bekannter Standard, so dass viele Programmierer bereits SQL sprechen, bevor sie sich mit ADO.NET beschäftigen. Außerdem lassen sich SQL-Kenntnisse auf alle anderen Datenbanksysteme übertragen. SQL ist wirklich universell. 2. SQL ist nicht umsonst so populär, da es für die Aufgaben, für die es einst geschaffen wurde, hervorragend geeignet ist. ADO.NET verlässt sich vollständig auf SQL für das Abfragen und Aktualisieren von Daten. Dies ist ein angenehmer Kontrast zum Vorgänger ADO, wo viele Aktionen »im Verborgenen« durchgeführt wurden und die Programmierer entsprechend keinen großen Einfluss auf das hatten, was hinter 124 Fragen jetzt lerne ich den Kulissen geschah. Ein »Nachteil« ist, dass die Programmierung dadurch etwas aufwändiger wird, denn der Programmierer muss sehr viel mehr in Eigenregie erledigen. 3.14 Fragen Wie lautet das SQL-Kommando, das die Vor- und Nachnamen aller Angestell- Frage 1 ten der Employees-Tabelle zurückgibt, die in Seattle wohnen? Wie lautet das SQL-Kommando, das die Vor- und Nachnamen aller Angestell- Frage 2 ten der Employees-Tabelle zurückgibt, die seit dem 1.1.1994 zur Firma gehören? Wie heißt der Angestellte der Northwind Company mit der längsten Betriebs- Frage 3 zugehörigkeit? Können Sie die Anzahl an Tagen, die dieser (bezogen auf den heutigen Tag) Mitglied der Firma ist, auch per SQL ausgeben? Wie lautet das SQL-Kommando, das die Anzahl der Tage, die alle Angestell- Frage 4 ten bereits Mitarbeiter der Firma sind, zusammen mit dem Nachnamen der Angestellten absteigend sortiert nach der Anzahl der Tage ausgibt? Wie lautet das SQL-Kommando, das den gesamten Umsatz der Northwind Frage 5 Company ausgibt? Wie lautet das SQL-Kommando, das den Nachnamen des Angestellten aus- Frage 6 gibt, der den meisten Umsatz gemacht hat? Die Lösungen zu den Fragen finden Sie in Anhang C. 125