SQL Server 2000 - Jürgen Bayer Informatik
Transcription
SQL Server 2000 - Jürgen Bayer Informatik
Jürgen Bayer SQL Server 2000 Installieren und Administrieren des SQL Servers, Implementieren von Sichten, Stored Procedures, Funktionen und Triggern Inhaltsverzeichnis 1 Einführung 1 1.1 Einige Begriffe zuvor 1 1.2 Die Editionen 2 Die Installation 5 2 2.1 Vorbereitungen 5 2.2 Installation des SQL Servers am Beispiel der Personal Edition 7 2.3 Diensteprogramme installieren 3 SQL Server Grundlagen 15 17 3.1 Das Client-Server Konzept im Vergleich zum File-Server 17 3.2 Client-Server Fachbegriffe 18 3.3 Der grundlegende Aufbau des SQL Servers 19 3.3.1 Die Tools des SQL Servers 20 3.3.2 Datenbanken 21 4 Grundlegende Operationen 24 4.1 Starten und Stoppen des SQL Server 24 4.2 Der Enterprise Manager 25 5 Erzeugen und Bearbeiten von Datenbanken 28 5.1 Erzeugen mit dem Enterprise Manager 28 5.2 Erzeugen mit SQL 35 6 6.1 Erzeugen und Verwalten von Tabellen Erzeugen von Tabellen mit dem Enterprise Manager 37 37 6.1.1 Die Datentypen 38 6.1.2 Primärschlüssel und Identity-Column 40 6.1.3 RowGUIDs 41 6.1.4 Indizes und Unique Constraints 41 6.2 Beziehungen zwischen Tabellen mit referentieller Integrität 49 6.3 Erstellen von Tabellen mit SQL 53 6.3.1 Primärschlüssel über mehrere Felder 54 6.3.2 Primärschlüssel mit nicht gruppiertem Index 54 6.3.3 Check-Einschränkungen 54 6.3.4 Indizes 55 6.3.5 Fremdschlüssel-Einschränkungen 55 6.3.6 Ändern von Einschränkungen 55 6.3.7 Ändern von Indizes 56 6.3.8 Informationen zu Spalten, Einschränkungen und Indizes 56 6.4 7 Ändern von Tabellen Benutzerverwaltung 56 57 7.1 SQL Server und Windows-Authentifizierung 57 7.2 Wie verwaltet der SQL Server die Rechte 57 7.3 Feste Server-Rollen, feste Datenbank-Rollen und benutzerdefinierte DatenbankRollen 58 7.4 Anlegen und Definieren von benutzerdefinierten Datenbank-Rollen und von Logins 59 7.4.1 Anlegen und Modifizieren von Rollen im Enterprise-Manager 60 7.4.2 Zuweisen und Verweigern von Rechten mit SQL 63 7.4.3 Anlegen und Modifizieren von Logins 64 7.5 Login 66 7.5.1 Login mit SQL Server-Authentifizierung 66 7.5.2 Login mit Windows-Authentifizierung 66 7.6 8 Spezielle Benutzernamen und Logins Sichten, Stored Procedures, Funktionen und Trigger 68 69 8.1 Einleitendes 69 8.2 Sichten 70 8.2.1 Erstellen einer Sicht 70 8.2.2 Verwenden von Sichten 71 8.2.3 Sortierungen in Sichten 71 8.2.4 Die Check-Option 72 8.2.5 Erweiterte Sicherheit mit Sichten 72 8.2.6 Sichten verändern 73 8.3 Stored Procedures 73 8.3.1 Erstellen von Stored Procedures 73 8.3.2 Rückgabetypen einer Stored Procedure 75 8.3.3 Parameter und Variablen 75 8.3.4 Aufruf von Stored Procedures am Beispiel eines VBA-Programms 77 8.3.5 Globale Variablen 80 8.3.6 TSQL-Kontrollstrukturen 81 8.3.7 TSQL-Operatoren 83 8.3.8 Stored Procedures mit Cursor 84 8.3.9 Stored Procedures verändern 86 8.4 Funktionen 86 8.4.1 Erstellen von Funktionen 86 8.4.2 Funktionen verändern 87 8.5 Trigger 88 8.5.1 Trigger erstellen 88 8.5.2 Die logischen Tabellen inserted und deleted 89 8.5.3 Rollback eines Triggers 93 8.5.4 Verändern von Triggern 94 8.6 Debuggen von Stored Procedures, Funktionen und Triggern 94 8.6.1 Grundlagen zum Debuggen 94 8.6.2 Das Beispiel 95 8.6.3 Der TSQL-Debugger 96 8.6.4 Der Debugger von Visual Studio .NET 99 9 Administrieren des SQL Servers 104 9.1 Die Größe des Transaktionsprotokolls 104 9.2 Backup und Restore 106 9.2.1 Die Wiederherstellungs-Modelle 107 9.2.2 Backup-Strategien 108 9.2.3 Backup von Hand 109 9.2.4 Restore 111 9.3 10 Der SQL Server Agent Tipps und Tricks 113 114 10.1 Manuelles Definieren einer Identity-Spalte für neue Datensätze 114 10.2 Temporäre Tabellen 114 11 11.1 12 Anhang Literaturverzeichnis Index 116 116 117 Bei der Installation und Verwendung des SQL Servers und in allen möglichen Artikeln und Büchern werden Sie immer wieder mit einigen Begriffen konfrontiert, die Sie vielleicht noch nicht kennen. Obwohl dieser Artikel die damit verbundenen speziellen Techniken nicht behandelt, beschreibe ich diese kurz. Dann wissen Sie wenigstens, warum es dabei prinzipiell geht . Die Datenbank-Engine ist das Herz des SQL Servers. Sie verwaltet die Daten und ermöglicht das Abfragen und Manipulieren der Daten über SQL. OLAP (Online Analytical Processing) ermöglicht es Benutzern, Daten unter den verschiedensten Gesichtspunkten abzufragen. So kann ein Abteilungsleiter z. B. alle Bestellungen von Produkten einer bestimmten Kategorie abfragen, die im Juli 2003 in die USA ausgeliefert wurden, diese mit Bestellungen von Produkten im selben Monat vergleichen, die innerhalb von Europa verkauft wurden und das Ganze mit Bestellungen aus Vormonaten vergleichen. OLAP ermöglicht es dem Benutzer, die Dimensionen der Abfrage (im Beispiel sind das die Produktkategorie, der Monat und die Zielregion) dynamisch auszuwählen und anzupassen. OLAP-Daten werden in so genannten multidimensionalen Datenbanken verwaltet, die es erst möglichen, Daten multidimensional abzufragen. Üblicherweise werden multidimensionale Datenbanken über spezielle Tools in regelmäßigen Abständen aus dem Daten einer normalen (relationalen oder objektorientierten) Datenbank generiert. Die OLAPFeatures des SQL Servers bieten Unterstützung bei der Erstellung und beim Füllen von multidimensionalen Datenbanken. Data-Mining (»nach Daten graben«) in ist ein eher allgemeiner Begriff, der aber sehr häufig im Zusammenhang mit Datenbanken auftaucht. Datamining wird in der Mathematik, der Kybernetik und der Genetik u. a. verwendet um herauszufinden, welche Daten in einer gegebenen Menge mit welchen anderen assoziiert sind und welche Daten in einer Folge von Ereignissen zu welchen anderen Daten führen. Bezogen auf Datenbanken ist mit Data-Mining im Prinzip dasselbe gemeint. In großen Unternehmen werden häufig so viele Daten gespeichert, dass ein genereller Überblick darüber nicht möglich ist. Datamining meint dann, dass in den Unternehmensdaten nach speziellen (in den Daten zunächst verborgenen) Informationen gegraben wird. Dazu gehört zum Beispiel, zu erkennen, nach welchem Muster Produkte verkauft werden (z. B. in welcher Region, in welchem Monat welches Produkt besser verkauft wird als andere). Hilfreich dabei ist natürlich OLAP. ! In Unternehmen werden und meist auch nicht Unternehmen liegen Datenbanksysteme oder Daten normalerweise nicht ausschließlich in einer einzigen Datenbank in einem einzigen Datenbanksystem verwaltet. In den meisten die Unternehmensdaten verstreut auf mehrere, verschiedene auch einfach nur in einer Vielzahl von Dateien (wie z. B. Excel- Einführung 1 Dateien) vor. Normalerweise ist es dann sehr schwierig, wenn Daten aus verschiedenen Quellen abgefragt werden müssen, um ein Problem zu lösen. Data-Warehousing steht nun dafür, dass in einem Unternehmen eine zentrale (»normale«) Datenbank in regelmäßigen Abständen mit den unterschiedlichen Unternehmensdaten oder Extrakten daraus gefüllt beziehungsweise aktualisiert wird. Über diese, rein zum Lesen gedachte Datenbank können die Daten des Unternehmens dann konsistent abgefragt werden. Der SQL Server bietet Unterstützung für Data-Warehousing über die die Data Transformation Services (DTS). " Der SQL Server 2000 kann auf verschiedenen Microsoft-Betriebssystemen und in verschiedenen Editionen installiert werden. Damit Sie wissen, welche Editionen was bietet und auf welchen Systemen Sie diese installieren können, beschreibe ich diese im Folgenden kurz. Eine nähere Beschreibung finden Sie im Microsoft-Dokument www.microsoft.com/sql/techinfo/planning/ChoosEd.doc. # Die Enterprise Edition bietet alle Features des SQL Servers. Sie ist extrem skalierbar und kann für einfache Unternehmensdatenbanken, aber auch für die größten Websites, für OLTP (Online Transaction Processing) und für Data-Warehousing-Systeme eingesetzt werden. Da diese Edition das so genannte »Failover Clustering« ermöglicht, können damit sehr große Datenbanken aufgebaut werden, die über mehrere Server verteilt werden und die beim Ausfall eines Servers weiter betrieben werden können. Die Enterprise Edition bietet Unterstützung für Rechner mit maximal 32 Prozessoren und bis zu 64 GB Arbeitsspeicher. Sie kann auf den folgenden Betriebssystemen installiert werden: • Windows 2000 Server • Windows 2000 Advanced Server • Windows 2000 Datacenter Server • Windows NT Server 4.0 • Windows NT Server 4.0 Enterprise Edition $ Diese Edition ist für kleinere und mittlere Unternehmen gedacht, die die erweiterte Skalierbarkeit, Verfügbarkeit und Performance und die erweiterten Analyse-Features der Enterprise Edition nicht benötigen. Ansonsten sind aber alle Features des SQL Servers, wie z. B. Standard-OLAP-Features, alle Data-Mining-Features und alle XML-Features enthalten. Die Standard Edition bietet gegenüber der Enterprise Edition u. a. die folgenden Features nicht: • erweitertes OLAP • auf mehrere Server verteilte Sichten auf die Daten • hohe Verfügbarkeit • indizierte Sichten • Analyse (OLAP) über das Web Die Standard Edition bietet Unterstützung für Rechner mit maximal vier CPUs und 2 GB Arbeitsspeicher und kann denselben Betriebssystemen installiert werden, wie die Enterprise Edition. Einführung 2 Die Personal Edition ist für den Standalone-Betrieb auf einem Desktop-PC oder einem Notebook vorgesehen. Sie ist gedacht für Anwendungen, die einen installierten SQL Server benötigen, aber auf Computern ausgeführt werden, die (evtl. nur zeitweise) nicht mit einem Server dem Unternehmen verbunden sind. Die Personal Edition beinhaltet prinzipiell dieselben Features wie die Standard Edition, mit den folgenden Ausnahmen: • Wenn mehr als fünf SQL-Anweisungsstapel gleichzeitig ausgeführt werden, wird die Performance automatisch reduziert; • Die Personal Edition kann lediglich zwei Prozessoren und maximal 2 GB Arbeitsspeicher nutzen (auf Windows 98 oder Me nur einen Prozessor); • Die Personal Edition kann nicht als »Verleger« (Subscriber) in einem replizierten System verwendet werden. Sie können die Personal Edition auf den folgenden Betriebssystemen installieren: • Windows XP Professional • Windows 2000 Professional • Windows 2000 Server • Windows 2000 Advanced Server • Windows 2000 Datacenter Server • Windows NT Workstation • Windows NT Server 4.0 • Windows NT Server 4.0 Enterprise Edition # Die Developer Edition ist prinzipiell identisch mit der Enterprise Edition und mit einer speziellen Lizenz versehen, die es Entwicklern erlaubt, mit dieser Editionen zu entwickeln und zu testen. Als Unternehmens-Server darf diese Edition natürlich nicht eingesetzt werden. Installiert werden kann die Developer Edition auf: • Windows XP Professional • Windows 2000 Professional • Windows 2000 Server • Windows 2000 Advanced Server • Windows 2000 Datacenter Server • Windows NT Workstation • Windows NT Server 4.0 • Windows NT Server 4.0 Enterprise Edition ! % & Die Windows CE Edition ist eine Version des SQL Servers, die unter Windows CE auf PocketPCs ausgeführt werden kann. Sie bietet lediglich einen grundlegenden Satz Funktionalität, wie z. B. grundlegende Features für relationale Datenbanken, Support für Transaktionen, RemoteDatenbankzugriff und für Replikationen. Die Windows CE Edition kann unter Windows CE ab Version 2.11 installiert werden. Einführung 3 # ' $ ( Die MSDE ist eine Version des SQL Servers, die nur den eigentlichen Datenbank-Server enthält. Alle erweiterten Features wie z. B. OLAP und alle Werkzeuge des SQL Servers (wie z. B. der Enterprise Manager) fehlen. Der SQL Server Agent, der für zeitgesteuerte Aufgaben, wie z. B. ein regelmäßiges Backup verwendet wird, ist allerdings in der MSDE enthalten. Im Prinzip ist diese Edition vergleichbar mit der Personal Edition, benötigt aber weniger Speicher. Das besondere an der MSDE ist, dass diese frei verteilt werden kann. Ein Entwickler, der eine Anwendung vertreiben will, die auf einer SQL-Server-Datenbank basiert, kann die MSDE der Installations-Version seiner Anwendung ohne weitere Kosten beilegen. Die MSDE können Sie auf den folgenden Betriebssystemen installieren: • Windows XP Professional • Windows 2000 Professional • Windows 2000 Server • Windows 2000 Advanced Server • Windows 2000 Datacenter Server • Windows NT Workstation • Windows NT Server 4.0 • Windows NT Server 4.0 Enterprise Edition Einführung 4 " " ) * Bevor Sie den SQL Server installieren sollten Sie einige Dinge überprüfen: $ Da das Installationsprogramm per Voreinstellung den aktuellen Computernamen als Servername verwendet, sollte dieser der SQL-Konventionen entsprechen. Der Name darf nur Buchstaben, Zahlen, Unterstriche, Hashes (#) und das Ampersand (&) enthalten und das erste Zeichen muss ein Buchstabe sein. Sie können den SQL Server aber auch so installieren, dass dieser nicht den Computernamen verwendet, sondern einen spezifischen. + , $- $ Der SQL Server verwendet zwei Dienste, die auf dem lokalen Rechner mit AdministratorRechten ausgestattet sein müssen (den SQL Server-Dienst und den SQL Server Agent-Dienst). Bei der Installation müssen Sie für beide Dienste entweder das System-Konto oder ein Benutzerkonto mit Administrationsrechten angeben. Sie können dabei wählen, ob beide Dienste unter demselben Konto oder unter unterschiedlichen Konten laufen. Sie sollten für diese Dienste ein oder zwei spezielle Benutzerkonten einrichten, deren Kennwort nicht abläuft und die das Kennwort nicht ändern können. Verwenden Sie auf keinen Fall ein Konto eines Benutzers (wie z. B. das Administrator-Konto). Wenn der entsprechende Benutzer sein Kennwort später ändert, können die Dienste ihre Arbeit nicht mehr aufnehmen. , * ) Der SQL Server 2000 erfordert die Installation des Internet Explorers ab Version 5.0. Unter NT ist zudem das Service Pack ab Version 5 erforderlich. . % Der SQL Server sollte auf einem System mit mindestens 64 MB Arbeitsspeicher installiert werden. Für die MSDE empfiehlt Microsoft mindestens 32 MB, für die Enterprise Edition mindestens 128 MB. An Festplattenspeicher benötigt der SQL Server 95 bis 250 MB. Da der SQL Server einmal abgefragte Daten in einem Cache zwischenspeichert, so dass diese bei der nächsten Abfrage wesentlich schneller verfügbar sind, sollten Sie so viel Arbeitsspeicher einbauen, wie möglich, wenn der SQL Server in einem Unternehmen eingesetzt wird. Da der SQL Server sehr prozessorintensiv arbeitet, empfiehlt sich der schnellste auf dem Markt erhältliche Prozessor. Wenn weniger als 100 Clients gleichzeitig auf den Server zugreifen, reicht ein Prozessor aus. Bei mehr als 100 Clients sollten Sie ein Mehrprozessorboard vorziehen. Der Windows-Performance Monitor hilft Ihnen mit der Anzeige der ProzessorVerwendung bei der Entscheidung, ob zusätzliche oder schnellere Prozessoren eingebaut werden müssen. Wenn das System durchschnittlich 70% oder für mindestens zehn Sekunden 90% des Prozessors verwendet, sollten Sie einen schnelleren oder einen zusätzlichen Prozessor einbauen. Bei den Festplatten sollten Sie auf jeden Fall SCSI einsetzen, besonders dann, wenn mehrere Platten eingebaut sind. Beim gleichzeitigen Zugriff auf mehrere Platten belastet SCSI den Prozessor weit weniger als IDE. IDE-Geräte können nicht gleichzeitig angesprochen werden, der Prozessor muss immer ein Gerät nach dem anderen ansprechen. Das ist besonders dann performance-mindernd, wenn ein (langsames) IDE-CD-ROM vorhanden ist und gleichzeitig mit einer Festplatte angesprochen wird. Ein SCSI-Controller sendet Anforderungen hingegen in eine Warteschlange im SCSI-Gerät. Das SCSI-Gerät meldet den Abschluss der Anforderung an Die Installation 5 den Controller zurück, der die Daten dann an den Prozessor weitergibt. So können gleichzeitig mehrere Anforderungen bearbeitet werden. In kleineren Unternehmen reicht eine Platte aus, die jedoch aus Sicherheitsgründen auf eine zweite Platte gespiegelt werden sollte (RAID 1). Bei hohen Datenanforderungen können Sie einzelne Datenbanken und auch Teile von Datenbanken (einzelne Tabellen und/oder das Transaktionsprotokoll) auf verschiedenen Platten erstellen, um den gleichzeitigen Zugriff zu beschleunigen. Die ideale Lösung (vgl. Delaney) ist die Installation des (sequentiell organisierten) Transaktionsprotokolls auf einem RAID 1-System und der Datenbanken auf einem separaten RAID 0+1-System1. Eine sehr ausführliche Abhandlung zu den Hardwareanforderungen finden Sie im Buch »Inside SQL Server 2000« von Kalen Delaney (ISBN 3860636197). Zur Installation müssen Sie als Administrator eingeloggt sein. 1 RAID 0 benutzt zwei Festplatten, die dem System als eine dargestellt werden. Daten werden in festgelegten Blöcken auf den beiden Platten verteilt. So wird die Performance von zwei Platten zur Speicherung und zum Lesen genutzt. Ein RAID 0,1-System spiegelt ein RAID-0-System zusätzlich auf ein weiteres RAID-0-System. Damit erhalten Sie gleichzeitig eine hohe Performance und eine hohe Sicherheit. Die Installation 6 "" ) $- $ # Nachdem Sie die Datei autorun.exe auf der Installations-CD aufgerufen haben, öffnet sich der Startdialog, in dem Sie neben der Installation auch einige Informationen abrufen können. Klicken Sie auf den Link SQL SERVER 2000-KOMPONENTEN © um die Installation zu starten. Im folgenden Dialog erhalten Sie die Möglichkeit, den Datenbank-Server und weitere Komponenten des SQL Servers wie z. B. die Analyse-Dienste (Analysis Services) und English Query zur installieren. Abbildung 1: Auswahl der zu installierenden Komponenten Den Datenbank-Server (den eigentlichen SQL Server) müssen Sie zumindest installieren. Die Analyse-Dienste und English Query sind optional. Die Analyse-Dienste bieten spezielle Features zur Verwendung von OLAP- und Datamining-Anwendungen. English Query ist ein spezielles Tool, das es Anwendern ermöglicht, Datenbanken mit nahezu normaler englischer Sprache an Stelle von SQL abzufragen. Klicken Sie also auf den Link DATENBANKSERVER INSTALLIEREN um den eigentlichen SQL Server zu installieren. Bestätigen Sie den Willkommens-Dialog und wählen Sie im nächsten Schritt, ob Sie den Server auf dem lokalen Computer oder auf einem entfernten Rechner installieren wollen. Im folgenden Schritt sollten Sie die erste Option wählen wenn Sie den SQL Server neu installieren. Die Option ERWEITERTE OPTIONEN ermöglicht im Vergleich dazu lediglich die Aufzeichnung einer speziellen »ISS«-Datei zur späteren unbeaufsichtigten Installation und die Wiederherstellung der Registrierung. Die Installation 7 Abbildung 2: Auswahl der Option zur Installation des SQL Servers Nachdem Sie in den folgenden Schritten ihren Namen eingegeben und der Lizenzvertrags bestätigt haben, können Sie wählen, ob Sie den Server komplett (inklusive MDAC und den Client-Tools zur Administration des Servers), nur die Client-Tools oder nur die Tools, die eine Verbindung zum SQL Server ermöglichen (MDAC, die »Microsoft Data Access Components«) installieren wollen. Für eine normale Installation wählen Sie die zweite Option. Abbildung 3: Auswahl der Server- und Cienttools für eine normale Installation Die Installation 8 Der nächste Schritt ermöglicht es, einen speziellen Instanznamen für den SQL Server einzurichten. Abbildung 4: Auswahl der Server- und Cienttools für eine normale Installation Ab der Version 2000 ermöglicht der SQL Server es, mehrere Instanzen auf einem Computer auszuführen. Standardmäßig wird eine Instanz benannt wie der Computer selbst. Wenn Sie eine weitere Instanz installieren, oder wenn Sie die Instanz anders benennen wollen, können Sie einen speziellen Instanznamen eingegeben. Ist bereits eine Instanz des SQL Servers (ab Version 7) mit dem Standardnamen installiert, müssen Sie sogar einen speziellen Instanznamen verwenden. Im nächsten Schritt können Sie die Installationsart und den Installationsort wählen. Wählen Sie die Option BENUTZERDEFINIERT um bei der Installation alle Optionen einstellen zu können. Die Installation 9 Abbildung 5: Auswahl der Installationsart und des Installationsortes Nachdem Sie auf WEITER geklickt haben können Sie nun die zu installierenden Komponenten wählen. Abbildung 6: Auswahl der zu installierenden Komponenten Schalten Sie die Option VOLLTEXTSUCHE ein, wenn Sie eine Volltextsuche ermöglichen wollen. Die Volltextsuche geht weit über die Möglichkeiten des LIKE-Operators in SQLAbfragen hinaus. Für die Komponente ENTWICKLUNGSTOOLS sollten Sie gegebenenfalls die Option API ZUM SICHERN/WIEDERHERSTELLEN einschalten. Mit dieser API können Sie externe Programme schreiben, die Datenbanken sichern bzw. wiederherstellen ohne den Enterprise Manager dazu zu verwenden. Die Installation 10 Im nächsten Schritt geben Sie ein oder mehrere Benutzerkonten an, unter denen die Dienste des SQL Servers ausgeführt werden sollen. Der SQL Server besteht im Wesentlichen aus den Diensten SQL Server (der SQL Server selbst) und SQL Server Agent (Dienst für zeitgesteuerte Jobs wie z. B. automatische Backups). Sie können für beide Dienste entscheiden ob diese unter dem Systemkonto oder unter einem speziellen Konto ausgeführt werden sollen. Abbildung 7: Einstellung der Konten für die SQL Server-Dienste Die Verwendung des Systemkontos ist dann ausreichend, wenn der SQL Server nicht auf andere, entfernte SQL Server zugreifen muss (was z. B. bei verteilten Datenbanken und bei Replikationen notwendig ist). Im anderen Fall sollten Sie ein oder zwei spezielle Konten für die Dienste des SQL Servers einrichten und diese mit (Domänen-)Administrationsrechten ausstatten. Verwenden Sie kein vorhandenes Benutzerkonto, bei dem es möglich ist, dass der Benutzer das Passwort ändert, da die Dienste des SQL Servers in diesem Fall nicht mehr starten. Die in diesem Dialog vorgenommenen Einstellungen können Sie später aber auch über den Windows-Dienste-Manager anpassen. Nach der Einstellung der Dienste-Konten wählen Sie, welchen Authentifizierungsmodus der SQL Server ermöglicht. Die Installation 11 Abbildung 8: Einstellung des Authentifizierungsmodus Hier sollten Sie den gemischten Modus einstellen und ein Kennwort für den Systemadministrator eingegeben. Die Windows-Authentifizierung ermöglicht es Benutzern, sich mit deren Windows-Login direkt auch in den SQL Server einzuloggen. Das erleichtert späteren Benutzern in einem Windows-System (idealerweise mit einer Domäne, in der die Benutzer verwaltet werden) die Arbeit mit Anwendungen, die Daten im SQL Server verwalten. Benutzer müssen sich dann nicht separat am SQL Server anmelden. Bei der anderen Art der Authentifizierung, der SQL-Server-Authentifizierung, werden dagegen spezielle Login-Namen im SQL Server verwaltet. Anwendungen, die diesen Modus verwenden, müssen sich explizit über einen dieser Namen im SQL Server einloggen. Da Sie beide Modi ermöglichen, können Sie den SQL Server auch dann administrieren wenn auf dem Computer, auf dem Sie die ClientTools verwenden, kein Administrator eingeloggte ist. Vergeben Sie dann aber auf jeden Fall ein nicht zu einfaches Kennwort für den Systemadministrator. Der Systemadministrator (der gleichzeitig auch mit dem Windows-Benutzer Administrator assoziiert wird) besitzt alle Rechte auf dem SQL Server und darf damit Aktionen ausführen, die auch zur Zerstörung einer Datenbank führen können. Im nächsten Schritt können Sie die Sortierung einstellen, die standardmäßig für Datenbankabfragen verwendet werden soll. Die Installation 12 Abbildung 9: Einstellung des Standardsortierung Die Sortierung bezieht sich auf SQL-Abfragen mit ORDER BY, GROUP BY oder ähnlichen Anweisungen. Die voreingestellten Werte entsprechen der Sortierung, die in Deutschland normalerweise verwendet wird. Sie können für Datenbanken, die mit anderen Systemen kommunizieren sollen, auch eine andere Sortierung einstellen. Das Hauptkriterium dazu ist der links oben einstellbare Unicode-Zeichensatz. Es ist verständlich, dass die chinesische Schrift eine vollkommen andere Sortierung besitzt als die westlichen Schriften, die mit dem Zeichensatz ISO Latin 1 (der der Einstellung LATIN1_GENERAL entspricht) abgebildet werden. Zusätzlich dazu können Sie noch einstellen, ob bei der Sortierung Groß- und Kleinschreibung und andere spezielle Dinge berücksichtigt werden. Zeichen-Vergleich Bedeutung Binär Wenn Sie diese Option einschalten (die alle anderen ausschließt) sortiert der SQL Server nach dem UnicodeWert der Zeichen. Groß-/Kleinschreibung beachten Groß- und Kleinbuchstaben werden unterschiedlich gewertet Unterscheidung nach Akzent Buchstaben mit Akzenten (z. B. á, à) werden ungleich Buchstaben ohne Akzenten gewertet Tabelle 1: Wichtige Sortierungs-Optionen Die Unterscheidung nach Kana ist für die japanische Sprache, die Unterscheidung nach Breite für bestimmte ostasiatische Sprachen wichtig. Im nächsten Schritt geben Sie an, welche Netzwerk-Bibliotheken installiert werden sollen. Voreingestellt ist TCP/IP. Die Installation 13 Abbildung 10: Einstellung der Netzwerk-Bibliotheken • Named Pipes ist kein Protokoll, sondern ein IPC2-Mechanismus, der auf verschiedenen Betriebssystemen verfügbar ist (z. B. neben Windows- auch auf UNIX- und LinuxSystemen). Named Pipes wird für die Kommunikation zwischen Prozessen verwendet, die auf demselben Computer ausgeführt werden. Damit ermöglicht Named Pipes ein Arbeiten mit dem SQL Server ohne ein funktionstüchtiges Netzwerk und hält Ihnen so eine Hintertür zum SQL Server offen für den Fall, dass das Netzwerk ausfällt. Wählen Sie dieses Protokoll also nicht ab. • TCP/IP-Sockets verwendet das TCP/IP-Protokoll zur Kommunikation mit dem Client. Laut Tests bei Microsoft ist dieses Protokoll das schnellste. Zudem müssen Sie das TCP/IPProtokoll verwenden, wenn der SQL Server über das Internet von Clients direkt3 angesprochen werden soll oder wenn Sie den SQL Server mit bestimmten Web-ServerAnwendungen, wie dem Microsoft Site Server verwenden. Installieren Sie dieses Protokoll also auf jeden Fall. Der per Default eingestellte Port 1433 ist der Standard-Port für den SQL Server. Nur wenn Sie mehrere SQL Server-Instanzen installieren macht es Sinn (bzw. ist notwendig), dass Sie den Port anpassen. • Multi-Protocol ist wie Named Pipes ebenfalls kein Protokoll, sondern ein IPCMechanismus, der verschiedene andere Protokolle (wie z. B. TCP/IP) verwenden kann. Multi-Protocol ermöglicht als einzige Bibliothek die Verschlüsselung von Daten zwischen Server und Client. Wenn ein SQL Server im Internet verfügbar sein soll, ist die Verschlüsselung oft ein wesentlicher Aspekt der Datensicherheit. Da Sie die MultiProtocol-Bibliothek so einstellen können, dass diese das TCP/IP-Protokoll verwendet, können Sie so z. B. auch im Internet Sicherheit gewährleisten. 2 Interprocess Communication 3 direkt meint, ein Client baut eine Verbindung zu einer SQL Server-Datenbank über das Internet auf, was in der Praxis eigentlich unüblich ist. Sinnvoll wäre die direkte Verbindung z.B., um einen SQL Server über das Internet administrieren zu können. Der Zugriff auf die Daten erfolgt im Internet üblicherweise über Mechanismen wie Active Server Pages (ASP) oder CGI-Skripts (die beide die Verbindung auf dem Web-Server aufbauen, der in der Regel eine direkte Netzverbindung zum SQL Server besitzt). Die Installation 14 • NWLink IPX/SPX müssen Sie installieren wenn das Netzwerk ein Novell-Netz ist. • AppleTalk ADSP müssen Sie installieren wenn Apple-Rechnern als Client auf den SQL Server zugreifen sollen. • Banyan VINES müssen Sie installieren wenn Rechner mit einem entsprechenden Betriebssystem als Client auf den SQL Server zugreifen sollen. Nachdem Sie diesen letzten Schritt bestätigt haben sind alle Einstellungen vorgenommen und der SQL Server beginnt (nach einem weiteren Info-Dialog) mit der Installation. "/ # Auf dem Server werden die notwendigen Diensteprogramme beim Setup per Voreinstellung automatisch mitinstalliert. Auf einem Client-Computer können Sie aber auch eine ausschließliche Diensteprogramm-Installation ausführen um die für die Administration notwendigen Tools auch auf einem anderem Rechner zur Verfügung zu haben. Tabelle 2 beschreibt die wichtigsten der Client-Diensteprogramme. Diensteprogramm Bedeutung Enterprise Manager Der Enterprise Manager ist das wichtigste Werkzeug zur Verwaltung des SQL Servers. Über dieses Programm können Sie alle administrativen Aufgaben ausführen. Profiler Der Profiler ist ein Tool zur Auswertung der Datenbankaktivitäten und zum Tuning und zur Überwachung der Leistung des SQL-Servers. Query Analyzer Der Query Analyzer ist ein wichtiges Windows-Programm zur einfachen Ausführung von SQL-Anweisungen. Tabelle 2: Die wichtigen Client-Diensteprogramme des SQL Servers Um diese Tools zu installieren starten Sie das Setup wie eine normale Installation und wählen dann in Schritt 6 die Option NUR CLIENTTOOLS. Die Installation 15 Abbildung 11: Installation der Client-Tools Die Installation 16 / $- $ 0 / $ & 2 1 # * , $ Beim klassischen File-Server übernimmt der Server lediglich die Aufgabe die Daten zu speichern und zu verwalten. Die Bearbeitung und Darstellung der Daten wird mit Hilfe einer Anwendung auf einem Client ausgeführt. Diese Vorgehensweise besitzt einige Nachteile: • die Netzbelastung ist sehr hoch; • die Wahrung der Datenintegrität und Konsistenz verbleibt größtenteils bei den Clients; • die Verwaltung der Benutzerrechte verbleibt bei den Clients. 3 Wenn ein Client Daten nach bestimmter Kriterien auswählen und anzeigen will ist beim FileServer-Konzept notwendig, dass im Idealfall zunächst nur die komplette Indexdatei über das Netz zum Client übertragen werden muss, damit dieser in der lokalen Kopie suchen kann. Kann nicht im Index gesucht werden, ist sogar die Übertragung der kompletten Datentabelle über das Netz notwendig. Wurde nur die Indexdatei geladen ist für jede Bewegung zwischen den Datensätzen wieder die Übertragung von einzelnen Datensätzen über das Netz notwendig. Obwohl moderne DBMS die Netzbelastung sicherlich durch intelligente Techniken reduzieren, ist diese dennoch sehr hoch. Die Ausführungsgeschwindigkeit der einzelnen Operationen hängt sehr von der Ausstattung der Einzelplatz-PCs und der Qualität des Netzwerks ab. Beim Client/Server-Konzept übernimmt der Server die Verwaltung der Daten und stellt den Clients auf Anfrage die gewünschte Datenmenge zur Verfügung. Als Abfragesprache dient SQL. Hier müssen lediglich die SQL-Anweisung und schließlich nur die Daten, die den Kriterien entsprechen, über das Netz transportiert werden. Die Ausführungsgeschwindigkeit hängt im Wesentlichen von der Ausstattung und Auslastung des Servers ab, die ClientComputer kommen mit relativ wenig Performance aus. 4 1 Ein Client-Server-Konzept besitzt im Server in der Regel wesentlich mehr Möglichkeiten zur Wahrung der Integrität und Konsistenz der Daten. Der SQL Server besitzt die folgenden Features zur Wahrung der Datenintegrität: • Datentypen, die den Typ der Daten festlegen, die in ein Datenfeld eingegeben werden können. • Regeln, die definieren, welche Werte in Datenfeldern eingegeben werden können (z. B. eine Artikelnummer nur zwischen 10.000 und 99.999). • Check Constraints, die Regeln ähnlich sind, im Gegensatz dazu jedoch mehrere Datenfelder einbeziehen können. • Deklarierte Referentielle Integrität (DRI), mit der Beziehungen mit referentieller Integrität zwischen Tabellen erstellt werden können. • Trigger, die bei einem Update, Insert oder Delete auf einer Tabelle TSQL-Skripts ausführen können und damit z. B. komplexe Referentielle Integrität gewährleisten oder laufende Summen berechnen können. SQL Server Grundlagen 17 /" & $ 2, * % Views (Sichten) sind lediglich eine andere Betrachtungsform einer oder mehrerer Tabellen. Views zeigen bestimmte Felder einzelner oder mehrere Tabellen gleichzeitig in einer temporären Ansicht. Auf Views können bis auf wenige Ausnahmen dieselben Operationen angewendet werden wie auf Tabellen. Ändert ein Anwender Daten in einer Sicht, so werden die zugrunde liegenden Tabellen entsprechend angepasst. $ , Eine Stored Procedure (Gespeicherte Prozedur) ist eine vorkompilierte Folge von SQLAnweisungen, die unter dem Namen der Prozedur von außen aufgerufen werden können. Der Microsoft SQL Server besitzt standardmäßig einige Gespeicherte Prozeduren, deren Name mit sp_ (Systemprozeduren) und xp_ (Erweiterte Systemprozeduren) beginnt. Benutzerdefinierte Stored Procedures werden verwendet, um die Performance für Abfragen zu erhöhen (Stored Procedures müssen im Gegensatz zu SQL-Abfragen nicht immer wieder kompiliert werden) und um Teile der Businesslogik4 einer Anwendung auf den Server auszulagern und damit leichter pflegbar zu machen. 5 Ein Trigger ist eine spezielle Stored Procedure, die immer dann automatisch aufgerufen wird, wenn eine Tabelle durch ein definiertes Ereignis verändert wird. Ein Trigger kann damit z. B. die Businesslogik (Business Rules) in der Datenbank aufrechterhalten. So ist die Abbuchung eines Artikels vom Lagerbestand z. B. nur dann möglich, wenn der Artikel lieferbar ist. Außerdem ist mit Triggern die Erhaltung der Referentiellen Integrität möglich wenn der Server keinen eigenen Mechanismus dazu besitzt (was bei modernen Systemen jedoch der Fall ist) oder der Mechanismus anders definiert werden soll als der Server-eigene Mechanismus. + '+ ( Regeln definieren, welche Daten in einzelnen Spalten einer Tabelle eingegeben werden können. Bei jeder Eingabe oder Änderung (INSERT oder UPDATE) eines Wertes überprüft der SQL Server den Wert mit Hilfe der für das betreffende Feld definierte Regel. , 4 '& ( Einschränkungen entsprechen dem ASCII-Standard und begrenzen die möglichen Werte, die in eine oder mehrere Spalten einer Tabelle eingegeben werden können. Einschränkungen können gleichzeitig mehreren Spalten zugewiesen werden. 6# Neben den Standarddatentypen können Sie eigene Datentypen definieren, die auf den Standarddatentypen basieren. Diese Benutzerdefinierte Datentypen können Sie als Datentyp für 4 Die Businesslogik definiert, wie und mit welchen Rechten auf Unternehmensdaten zugegriffen werden kann. In klassischen 2-Schichten-Systemen, die eine Desktop-Datenbank verwenden, ist die Businesslogik zwangsweise in den Clients implementiert. Client/Server-Datenbanken ermöglichen, Teile der Businesslogik über Stored Procedures und Trigger auf den Datenbankserver auszulagern und damit die Pflege der Businesslogik erheblich zu erleichtern. In modernen 3- oder n-Schichten-Systemen wird die Businesslogik übrigens in der mittleren Schicht, der Businesslogik-Schicht, in Form von COM- bzw. CORBA-Objekten untergebracht. Stored Procedures spielen jedoch auch hier eine Rolle. SQL Server Grundlagen 18 Spalten und Parameter für Gespeicherte Prozeduren verwenden. Benutzerdefinierte Datentypen unterscheiden sich in den verschiedenen DBMS. // $- $ Der SQL Server besteht aus mehreren Diensten, die bei Windows XP, 2000 und NT als Dienst und bei Windows 98 und Me als exe-Datei vorliegen. Der MSSQLServer-Dienst arbeitet auf der untersten Ebene, verwaltet alle Dateien, aus denen die Datenbanken aufgebaut sind und ist dafür verantwortlich, SQL-Anweisungen zu verarbeiten, Ergebnisse zu den Clients zurückzusenden und Systemressourcen zu allozieren. Der SQLServerAgent-Dienst führt zeitgesteuerte Jobs aus und ist für Warnungen zuständig. Ein zeitgesteuerter Jobs kann z. B. das tägliche Backup der Datenbank sein. Der Microsoft Distributed Transaction Coordinator (MSDTC) ist verantwortlich für die Koordination von Transaktionen, die über mehrere (u. U. entfernte) Datenbanken ausgeführt werden. Auf den Clients und dem Server laufen zudem eine Client- und eine Server-NetzwerkBibliothek, die die Verbindung mit den Clients über das Netzwerk ermöglichen und auf dem Server der Open Data Service (ODS), eine Schnittstelle zwischen der Netzwerkbibliothek und dem MSSQLServer-Dienst. Auf der Clientseite kann ein Client über verschiedene Komponenten Verbindung mit dem Server aufnehmen: über ODBC (direkt oder über DAO, RDO oder ADO), OLE DB (ADO), ADO.NET und über die SQL Server DB-Bibliotkek. Im Hinblick auf zukünftige Entwicklungen und die Erweiterbarkeit einer Anwendung sollte der Zugriff wohl ausschließlich über ADO oder ADO.NET erfolgen. Die Microsoft Data Access Components (MDAC), von denen ADO ein Bestandteil ist, beinhalten einen nativen Provider für den SQL Server. Der SQL Server 2000 installiert MDAC 2.6 bereits auf dem Server. Sie können die aktuelle MDAC-Version außerdem von der Microsoft Website herunterladen (www.Microsoft.com/data). ADO.NET, das Bestandteil des .NET-Framework ist, enthält ebenfalls einen nativen Provider. SQL Server Grundlagen 19 // 5 $- $ Eine komplette Installation des SQL-Servers installiert einige Tools, die in Tabelle 3 beschrieben werden. Diese Tools finden Sie im Ordner 80\Tools\Binn der SQL ServerInstallation, sofern diese nicht über den Eintrag im Startmenü verfügbar sind. Tool Bedeutung Enterprise Manager Der Enterprise Manager (SQL Server Enterprise Manager.msc) ist das wichtigste Werkzeug zur Verwaltung des SQL Servers. Dieses Microsoft Management Console (MMC)-Tool ermöglicht es dem Administrator, alle Einstellungen des SQL Servers und der Datenbanken anzupassen und Datenbanken inklusive deren Tabellen anzulegen und zu modifizieren. Profiler Der Profiler (profiler.exe) ist ein Tool zur Auswertung der Datenbankaktivitäten, zum Tuning und zur Überwachung der Leistung des SQL-Servers. Query Analyzer Der Query Analyzer (isqlw.exe) ist ein sehr wichtiges WindowsProgramm zur einfachen Ausführung von SQL-Anweisungen. BCP Das Bulk Copy Programm (bcp.exe) wird zum kommandozeilenbasierten Im- und Exportieren von Daten zwischen SQL Server-Datenbanken und Textdatenbanken verwendet. DTS DTS (Data Transformation Service) ist ein einfach zu verwendendes Windows-Tool (dtsrunui.exe) zum Import und Export von Daten zwischen verschiedenen Datenbanken. Da DTS auf OLE DB basiert, können Sie damit Daten zwischen allen Datenbanken austauschen, für die ein OLE DB-Provider verfügbar ist (z. B. SQL Server-, Oracle-, Access- und alle Datenbanken, für die ein ODBC-Treiber verfügbar ist). DTS wird vorwiegend für Data-Warehousing-Szenarien eingesetzt, bei denen Daten externer Datenquellen in eine SQLServer-Datenbank importiert werden. SQL Server Clientkonfiguration Die SQL Server-Clientkonfiguration (cliconfg.exe im WindowsSystemordner) wird verwendet, um die von Clients zu verwendende Netzwerk-Bibliothek einzustellen. Viele von den Clients verwendete Bibliotheken, wie z. B. ODBC ermöglichen eine separate Einstellung der Netzwerk-Bibliothek, hier benötigen Sie dieses Tool nicht. SQL ServerNetzwerkkonfiguration Die SQL Server-Netzwerkkonfiguration (svrnetcn.exe) ermöglicht Ihnen die Einstellung der zu verwendenden Netzwerk-Bibliotheken auf dem Server. Service Manager Der Service Manager (sqlmangr.exe) ist ein einfaches Tools zum Starten, Stoppen und Beenden der SQL Server-Dienste. Tabelle 3: Die Diensteprogramme des SQL Servers Die meisten dieser Tools können Sie auch über das EXTRAS-Menü des Enterprise Managers aufrufen. SQL Server Grundlagen 20 //" Jede SQL Server-Datenbank ist in mindestens zwei Dateien gespeichert, der Datenbankdatei und der Datei für das Transaktions-Protokoll (siehe unten). Eine Datenbank kann aber auch auf mehrere Dateien aufgeteilt werden, was bei großen Datenbanken sinnvoll sein kann, wenn statt einer großen Festplatte aus Performancegründen mehrere kleine Festplatten verwendet werden. Der SQL Server installiert per Default die folgenden Datenbanken: Datenbank Bedeutung master In dieser Datenbank wird der SQL Server verwaltet. So sind z. B. die Benutzerkonten, derzeit laufende Prozesse, Systemfehlermeldungen und Informationen über die Datenbanken des Servers in der master-Datenbank gespeichert. model Diese Datenbank wird als Voreinstellung für die Erzeugung neuer Datenbanken verwendet. Neue Datenbanken erhalten die Struktur, die in der modelDatenbank voreingestellt ist. Sie können die Struktur der model-Datenbank an Ihre Bedürfnisse anpassen, wenn das auch nur selten Sinn macht. msdb Der SQL Server Agent und dessen Konfigurationstools verwenden diese Datenbank zur Speicherung der auszuführenden Jobs und der zu überwachenden Systemwerte. Northwind Eine Beispieldatenbank, die Bestelldaten speichert Pubs Eine Beispieldatenbank, die Daten über Computer-Literatur verwaltet und im Aufbau der biblio.mdb von Visual Basic ähnelt. tempdb In dieser Datenbank legt der SQL Server intern temporäre Tabellen an, die beim Sortieren und bei einigen Verknüpfungsoperationen benötigt werden. Zudem werden explizit erzeugte temporäre Tabellen ebenfalls in der tempdb-Datenbank angelegt. Die tempdb-Datenbank wird bei jedem Neustart des SQL Servers neu erzeugt. Tabelle 4: Die Default-Datenbanken des SQL Servers Sie sollten niemals Änderungen direkt in der master- und der msdb-Datenbank vornehmen. Alle notwendigen Einstellungen können Sie auch über SQL oder den Enterprise-Manager vornehmen. Änderungen in diesen Datenbanken können ein Fehlverhalten des SQL Servers oder im schlimmsten Fall einen Ausfall des SQL Servers verursachen. 5 # '5 , ( Als Transaktion bezeichnet man in der Client Server-Welt eine Gruppe von Datenbankoperationen, die eine logische Einheit bilden. Diese Gruppe kann nur komplett ausgeführt werden. Bei einem Fehler innerhalb der Transaktion werden alle bereits ausgeführten Operationen rückgängig gemacht. Dies gewährleistet die Konsistenz der Daten in der Datenbank. Eine Client/Server Datenbank unterscheidet implizite und explizite Transaktionen. Eine implizite Transaktionen wird bei jedem Ändern, Anfügen oder Löschen einer oder mehrerer Datenbankzeile (über die SQL-Anweisungen UPDATE, INSERT bzw. DELETE) vom SQL Server selbst ausgeführt. Wenn Daten geändert, angefügt oder gelöscht werden, verfolgt der SQL Server diese Änderungen im Transaktionsprotokoll der Datenbank. Dabei werden alle tatsächlich ausgeführten Operationen aufgezeichnet. Wenn Sie z. B. einen Datensatz ändern, wird der SQL Server die Originalzeile zwischenspeichern, löschen, ändern, eine neue Zeile anfügen und alle abhängigen Indizes anpassen. Alle diese Operationen werden im SQL Server Grundlagen 21 Transaktionsprotokoll aufgezeichnet. Bei einem Fehler innerhalb der Datenänderungen (z. B. weil der Strom ausgefallen ist), kann der SQL Server beim Neustart die Datenbank „recovern“. Eine explizite Transaktion startet ein Anwender oder eine Anwendung über die SQLAnweisung BEGIN TRANSACTION. Wenn die Transaktion als erfolgreich gewertet wird, wird diese mit COMMIT TRANSACTION abgeschlossen. Eine nicht erfolgreiche Transaktion kann mit ROLLBACK TRANSACTION verworfen werden. Das klassische Beispiel für eine explizite Transaktion ist die Umbuchung eines Geldbetrags von einem Konto zum andern. Vor dem Abbuchen des Betrags vom Quellkonto wird die Transaktion gestartet. Nach dem Abbuchen wird der Betrag dem Zielkonto zugebucht. Nur wenn weder beim Ab- noch beim Zubuchen ein Fehler aufgetreten ist, wird die Transaktion mit COMMIT TRANSACTION abgeschlossen. Tritt z. B. beim Zubuchen ein Fehler auf, weil der Datensatz gerade gesperrt ist, wird die Transaktion mit ROLLBACK TRANSACTION verworfen und damit auch das Abbuchen erst gar nicht in der Datenquelle gespeichert. Ein weiteres Beispiel ist eine Anwendung, die in einem Reisebüro das Buchen einer Reise ermöglicht. Ein Kunde, der eine Reise buchen will, muss zunächst in der Kundentabelle angelegt werden. Danach wird der Flug in die Flugtabelle und das Hotel in die Hoteltabelle gebucht. Schließlich wird noch eine Buchung in der Finanzbuchhaltung eingefügt, damit dem Kunden eine Rechnung gedruckt werden kann. Kurz vor dem Ausdruck der Rechnung entscheidet sich der Kunde anders und verlässt das Reisebüro. Schön, wenn das Ganze in einer Transaktion eingeschlossen ist und diese dann einfach verworfen werden kann. 7& , 5 Transaktionen werden im SQL Server folgendermaßen ausgeführt: Der SQL Server verwaltet Daten immer auf so genannten Seiten (Pages). Eine Seite besitzt eine Größe von 8 KB, eine Datenbank ist also im Prinzip eine Sammlung aus 8 KB großen Datenseiten (daneben existieren noch weitere Seiten, wie z. B. die, auf denen die Indizes verwaltet werden). Eine Datenseite speichert einen oder mehrere komplette Datensätze, die aufgrund der Seitenarchitektur eine Größe von maximal 8096 Byte besitzen können (die restlichen Bytes werden für den Seitenkopf und ein Zeilen-Offset-Array auf der Seite verwendet). Ein Datensatz kann nicht über mehrere Seiten verwaltet werden. Im Seitenkopf werden u. a. Informationen zur Datenbank, zur physikalischen Datei der Seite und die Nummer der Seite verwaltet. So kann eine Seite eindeutig zugeordnet werden. Wenn nun Datensätze geändert, gelöscht oder hinzugefügt werden, überprüft der SQL Server zunächst, ob die betreffende Seite bereits im Arbeitsspeicher verwaltet wird. Ist dies nicht der Fall, liest er die Seite ein. Diese Verwaltung der Daten im Speicher bewirkt nebenbei ein sehr effizientes Caching von Daten: Einmal eingelesene Seiten müssen beim nächsten Lesen nicht mehr aus der Datei gelesen werden, sondern können dem wesentlich schnelleren Arbeitsspeicher entnommen werden. Alle Änderungen werden nun zunächst ausschließlich im Arbeitsspeicher vorgenommen. Die Datenseite wird dann über ein spezielles Flag als „Dirty“ gekennzeichnet. An diesem Punkt unterscheiden sich die Daten der Seite im Arbeitsspeicher und in der Datei. Wenn die Transaktion über COMMIT abgeschlossen oder über ROLLBACK verworfen wird, und die Änderungen im Arbeitsspeicher abgeschlossen sind, schreibt der SQL Server die Transaktion in das Transaktionsprotokoll. Dabei speichert der SQL Server einen Datensatz, der den Beginn der Transaktion kennzeichnet, weitere Datensätze mit den vorherigen und den neuen (geänderten) Daten und einen Datensatz, der das Ende der Transaktion kennzeichnet (Commit oder Rollback). Beim Hinzufügen eines Datensatzes speichert das Protokoll den kompletten neuen Datensatz, beim Löschen den gelöschten und beim Ändern den vorherigen und den neuen (geänderten) Datensatz. Diese Daten werden jeweils in einem Datenfeld des Protokolls in binärer Form verwaltet. Alle Datensätze einer Transaktion werden mit einer eindeutigen Transaktions-ID und einer aufsteigenden Log Sequenz Nummer (LSN) gekennzeichnet, damit diese Transaktion von anderen unterschieden und in der korrekten Reihenfolge identifiziert werden kann. SQL Server Grundlagen 22 Wenn Sie das Ganze einmal life beobachten wollen, fügen Sie einer Tabelle in einer Datenbank z. B. einen Datensatz hinzu und schauen sich im Query Analyzer dann über dbcc log (Datenbankname, type=4) die Einträge im Transaktionsprotokoll an. & ,# Die im Arbeitsspeicher geänderten Daten müssen nun noch in die physikalische Datei geschrieben werden. Dafür läuft im SQL Server ein so genannter Lazywriter-Thread. Dieser Thread überprüft an so genannten Checkpoints (die per Default einmal pro Minute auftreten), ob Datenseiten mit dem Dirty-Flag und einer (mit Commit) abgeschlossenen Transaktion existieren und wie viele Änderungen geschrieben werden müssen. Findet der Thread eine ausreichend große Menge an Änderungen, beauftragt er einen weiteren Thread (einen Worker-Thread) damit, alle geänderten Datenseiten in die jeweilige Datei zurückzuschreiben und das Dirty-Flag zurückzusetzen. Gleichzeitig wird der Beginn des aktiven Teils des Transaktionsprotokolls auf die LSN gesetzt, die der letzten der geschriebenen LSNs folgt. Die geschriebenen LSNs verbleiben dann im so genannten wiederherstellbaren Teil des Protokolls (der für BackupStrategien benötigt wird). Nur die LSNs im aktiven Teil werden bei einem Checkpoint berücksichtigt. Die Frequenz der Checkpoints können Sie als globale Einstellung im SQL Server anpassen. , + , Fällt der SQL Server einmal aus (weil z. B. der Strom ausfällt oder der Rechner abstürzt) wird beim nächsten Hochfahren automatisch ein Wiederherstell-Prozess gestartet. Dieser Prozess überprüft den aktiven Teil des Transaktionsprotokolls auf Änderungen, die noch nicht in die Datenbanken geschrieben wurden. Alle Transaktionen, die mit Commit abgeschlossen sind, werden dann in die physikalischen Dateien geschrieben. Transaktionen, die gar nicht oder mit Rollback abgeschlossen sind, werden dabei nicht geschrieben. Damit stellt der SQL Server sicher, dass abgeschlossene Transaktionen auch komplett geschrieben werden und nicht abgeschlossene das System nicht in einen inkonsistenten Zustand versetzen können. Alle nicht abgeschlossenen Transaktionen müssen dann noch einmal nachvollzogen werden. Alternativ zum automatischen Wiederherstellen können Sie auch ein manuelles Wiederherstellen ausführen, bei dem Sie den Prozess kontrolliert ausführen können. 5 , # Transaktionen besitzen ebenfalls eine Bedeutung bei Backup-Strategien. Jede SQL Server Datenbank sollte regelmäßig gesichert werden. Der SQL Server bietet dazu einen recht einfach anzuwendenden Mechanismus, der sogar erlaubt, ein automatisches Backup zu bestimmten Zeiten (über den SQL Server Agent) zu erzeugen. Da ein Backup einer kompletten Datenbank viel Platz benötigt und die meisten Firmen mehrere Backups verwalten, wird häufig die Datenbank nur einmal pro Woche gesichert. Jeden Tag wird dann allerdings das Transaktionsprotokoll gesichert. Wenn die Datenbank beschädigt wird, kann der SQL Server die kompletten Daten mit Hilfe des letzten Datenbank-Backups und der nachfolgenden Transaktionsprotokoll-Backups wiederherstellen. $6 Der Systemkatalog ist aus Tabellen in der Master-Datenbank aufgebaut und speichert u. a. die Konfiguration des SQL Servers und Informationen über enthaltene Datenbanken. Spezielle Einstellungen der Datenbanken werden in Systemtabellen innerhalb jeder Datenbank verwaltet. Die Namen dieser Tabellen beginnen immer mit »sys«. SQL Server Grundlagen 23 8 0 8 # $ $ ## $- $ Wenn der SQL Server nicht automatisch beim Windows-Start gestartet wird, können Sie den Server mit dem Dienst-Manager interaktiv starten. Abbildung 12: Der Dienst-Manager des SQL Servers Mit demselben Programm können Sie den SQL-Server-Dienst und die anderen Dienste des SQL Servers pausieren und beenden. Daneben können Sie aber auch den Enterprise Manager verwenden, um den Server zu starten und zu beenden. Den korrekten Start des Servers können Sie mit dem Query Analyzer überprüfen. Wenn Sie in Windows als Administrator eingeloggt sind, geben Sie nach dem Start des Query Analyzers im automatisch erscheinenden Login-Dialog an, dass Sie die Windows-Authentifizierung verwenden wollen. Abbildung 13: Login in den SQL Server im Query Analyzer Wählen Sie dann im Abfragefenster im Feld DB die Datenbank Northwind (eine der Beispieldatenbanken) aus und geben Sie folgende SQL-Anweisung ein: SELECT * FROM Products Grundlegende Operationen 24 Abbildung 14: Abfrage im Query Analyzer Nach der Ausführung, die Sie über den Schalter mit dem grünen Pfeil oder über F5 starten, erscheint das Ergebnis im unteren Bereich des Abfrage-Fensters. 8" # Mit dem Enterprise Manager verwalten Sie einen oder mehrere SQL Server. Bei der Installation hat das Installationsprogramm bereits alle im aktuellen Netzwerk erreichbaren SQL Server im Enterprise Manager registriert. Normalerweise müssen Sie also nichts weiter machen um die im lokalen Netz verfügbaren SQL Server administrieren zu können. Wenn Sie einen lokalen SQL Server nachträglich oder einen entfernten SQL Server registrieren müssen, finden Sie Hinweise dazu im folgenden Abschnitt. $ + Um einen SQL Server zu administrieren muss dieser im Enterprise Manager registriert sein. Da Sie im Enterprise Manager mehrere SQL Server verwalten können, können Sie mehrere Gruppeneinträge einrichten (per Voreinstellung besteht nur eine Gruppe »SQL SERVERGRUPPE«), um die Übersicht zu gewährleisten. Wenn Sie einen (lokalen oder entfernten) SQL Server im Enterprise Manager registrieren wollen, können Sie dies über den Befehl NEUE SQL SERVER REGISTRIERUNG im Kontextmenü des Gruppeneintrags im Enterprise Manager erledigen. Im erscheinenden, wenig hilfreichen Assistenten wählen Sie idealerweise die Option, dass Sie die Registrierung ab sofort ohne den Assistenten ausführen wollen. Im dann erscheinenden Registrierungs-Dialog geben Sie die Registrationsdaten des SQL Servers an. Grundlegende Operationen 25 Abbildung 15: Registration eines SQL Servers ohne Assistent Wählen Sie den Namen des SQL Servers aus der Server-Liste aus oder geben Sie den Namen ein. (Netz-)lokale SQL Server, die in der Liste nicht auftauchen, können Sie auch über den Schalter mit den drei Punkten neben der Liste ermitteln. Für die Registrierung bietet sich immer die Windows-Authentifizierung an wenn Sie als Administrator eingeloggt sind und wenn der andere SQL Server in derselben Benutzerdomäne oder in einer Domäne oder auf einem Rechner ausgeführt wird, der ein identisches Administratorkonto besitzt (wenn der SQL Server also das Administratorkonto kennt). Damit erreichen Sie, dass Sie sich nicht extra in den SQL Server einloggen müssen um diesen zu administrieren. Ist dies nicht möglich, wählen Sie die SQL Server-Authentifizierung. In diesem Fall Sie beim Login ein gültiges SQL-Server-Administratorkonto (üblicherweise ist das das sa-Konto) mit dessen Passwort angeben. Wählen Sie in diesem Fall in einer Produktions-Umgebung auf jeden Fall die Option BENUTZERNAME UND KENNWORT IMMER ANGEBEN. Damit stellen Sie sicher, dass ein Benutzer, der den Enterprise Manager gestartet hat, auf jeden Fall ein gültiges SQL-Server-Administratorkonto und dessen Passwort angeben muss, um eine Verbindung zum SQL Server aufbauen zu können. Geben Sie stattdessen bei der Registration ein Benutzerkonto und dessen Passwort fest an, kann jeder Benutzer ohne weiteres der SQL Server administrieren, da die Login-Daten fest gespeichert werden. Nach dem Start des Enterprise Managers können Sie die Objekte der einzelnen SQL Server hierarchisch auflisten. Grundlegende Operationen 26 Abbildung 16: Der Enterprise Manager mit drei registrierten SQL Servern (dem lokalen, einer entfernten SQL-Server- und der lokalen MSDE-Instanz) Die einzelnen Objekte können Sie hauptsächlich über das Kontextmenü (Rechtsklick auf dem Objekt) bearbeiten. Der Enterprise-Manager zeigt standardmäßig neben den benutzerdefinierten Datenbanken und Datenbank-Objekten auch alle System-Datenbanken und System-Objekte an. Bei den Datenbanken sind das die Datenbanken master, model, msdb und tempdb. Bei den Tabellen und Sichten sind das alle, die mit „sys“ beginnen. Da Sie diese in der Praxis eigentlich fast nie (oder nur sehr selten) benötigen, und besonders die Systemtabellen die Übersicht über eine Datenbank erschweren, ist es vorteilhaft, wenn Sie die Ansicht der Systemobjekte ausschalten. Die entsprechende Option finden Sie in den Eigenschaften der Registrierung eines SQL Servers: Klicken Sie mit der rechten Maustaste auf den Eintrag des SQL Servers, wählen Sie EIGENSCHAFTEN DER SQL SERVER-REGISTRIERUNG BEARBEITEN und schalten Sie in den Eigenschaften die Option SYSTEMDATENBANKEN UND SYSTEMOBJEKTE ANZEIGEN aus. Grundlegende Operationen 27 9 9 # Vor dem Erzeugen, Vergrößern oder Verkleinern einer Datenbank sollten Sie die Master-Datenbank sichern um das Wiederherstellen des Systems im Fehlerfall zu erleichtern. Der Befehl NEUE DATENBANK im Kontextmenü des DATENBANKEN-Ordners öffnet den Dialog zur Erstellung einer neuen Datenbank. Abbildung 17: Dialog zum Erzeugen von Datenbanken und Ändern der grundsätzlichen Eigenschaften der Datenbank Standardmäßig wird die Datenbankdatei im Unterordner data in dem Ordner erstellt, indem Sie den SQL Server installiert haben. Per Voreinstellung ist das der Ordner C:\Programme\Microsoft SQL Server\data. Über die Register DATENDATEIEN und TRANSAKTIONSPROTOKOLL können Sie jedoch auch jeden anderen Ordner für Dateien der Datenbank angeben. Erzeugen und Bearbeiten von Datenbanken 28 Abbildung 18:Einstellung des Speicherorts und der Eigenschaften der Datenbankdatei Die Einstellung ANFANGSGRÖßE definiert, wie groß die Datenbank bei der Erstellung ist. Ein MB ist für neue Datenbanken in der Regel ausreichend, wenn Sie die Option DATEI AUTOMATISCH VERGRÖSSERN eingeschaltet haben. Wenn Sie diese Option jedoch ausschalten, sollten Sie die Erstellungsgröße auf einen größeren Wert einstellen. Die Option DATEI AUTOMATISCH VERGRÖSSERN bewirkt, dass der SQL Server die Datenbankdatei automatisch vergrößert, wenn diese zu einem bestimmten Prozentsatz gefüllt ist. Damit erreichen Sie, dass der SQL Server nie Schwierigkeiten mit der Größe der Datenbank bekommt (sofern noch genügend Platz auf der Festplatte verfügbar ist). Sie sollten diese Option normalerweise nicht abschalten und der Datenbank genügend freien Platz auf den Festplatten des Systems gönnen. Für diese Option können Sie zusätzlich einstellen, ob die Datei in festgelegten MB-Einheiten oder prozentual vergrößert wird. Eine Vergrößerung in MB kann sinnvoll sein, wenn beim Betrieb der Datenbank regelmäßig immer nahezu dieselbe Anzahl an Datensätzen hinzugefügt wird. Eine Vergrößerung in Prozent bewirkt, dass die Datenbank nach einer anfänglichen Initialisierungsphase nur noch selten oder gar nicht mehr vergrößert wird. Diese Option bewirkt in der Regel größere Datenbankdateien als die Vergrößerung in MB. Bei der Entscheidung der Dateivergrößerungs-Option müssen Sie beachten, dass das Vergrößern einer Datei recht viel Zeit in Anspruch nimmt. In einem System, das hoch verfügbar sein muss, sollten Sie deshalb eine möglichst hohe Anfangsgröße und eben so hohe Dateivergrößerungs-Werte angeben. Im Feld MAXIMALE DATEIGRÖßE können Sie daneben noch einstellen, ob und wie die maximale Dateigröße eingeschränkt ist. Mit der Voreinstellung ist die Größe nur auf den maximal freien Platz auf der Festplatte eingeschränkt. Erzeugen und Bearbeiten von Datenbanken 29 Der SQL Server ermöglicht die Anlage von Datenbanken in mehreren Dateien. Geben Sie dazu einfach mehr als einen Dateinamen an. Die erste der angegebenen Dateien ist übrigens die so genannte primäre Datei. Die Anlage in mehreren Dateien kann Performancevorteile bringen, wenn die einzelnen Dateien auf verschiedenen Festplatten angelegt werden und besitzt u. U. Vorteile bei Backup-Strategien für sehr große Datenbanken. Beim späteren Anlegen von Tabellen können Sie bei einer aus mehreren Dateien bestehenden Datenbank entscheiden, in welcher Datei die Tabelle angelegt wird. So können Sie eine Datenbank unter Umständen so optimieren, dass Tabellen, die häufig gleichzeitig abgefragt werden (z. B. über Abfragen mit Joins), in verschiedenen Datenbankdateien (und damit idealerweise auf verschiedenen Festplatten) angelegt werden. Damit nutzen Sie dann die volle Performance von gleich zwei Festplatten bei Abfragen über diese Tabellen. Ob eine solche Architektur in der Praxis sinnvoll und Performance-steigernd ist, kann leider so ohne weiteres nicht beantwortet werden. Im Prinzip hilft nur ein Ausprobieren. Wenn Sie z. B. bereits ein System einsetzen, das mit schnellen SCSI-Festplatten auf einem RAID 0, RAID 0+1 oder RAID 5-System arbeitet, und das mit sehr viel Arbeitsspeicher ausgestattet ist, ist es fraglich, ob eine Aufteilen der Datenbank auf verschiedene Festplatten überhaupt Sinn macht. Sinnvoll kann das Aufteilen für spezielle Backup-Strategien sein. Bei einer gesplitteten Datenbank können Sie die einzelnen Dateien auf mehreren kleineren Festplatten restaurieren und benötigen nicht unbedingt eine große Festplatte mit ausreichend viel Platz. Im Notfall, wenn die Datenbank schnell wieder laufen muss, haben Sie vielleicht keine große Festplatte, aber (evtl. aus den Client-Computern) mehrere kleinere zur Verfügung. Über der Einstellung DATEIGRUPPE können Sie mehrere Dateien in einzelnen Dateigruppen anlegen. Mit Dateigruppen können Sie die Performance erhöhen, indem Sie festlegen, in welchen Dateigruppen (die in der Regel auf verschiedenen Festplatten angelegt werden), die Systemtabellen und in welchen die verschiedenen Basistabellen und Indizes angelegt werden (beim Erstellen von Tabellen und Indizes können Sie festlegen, in welcher Dateigruppe diese angelegt werden). Tabellen und Indizes, auf die häufig zugegriffen wird, können Sie z. B. in einer Dateigruppe anlegen, deren Dateien auf einer sehr schnellen Festplatte gespeichert sind. Dateigruppen können zudem Sinn machen, wenn nur Teile der Datenbank über ein Backup gesichert werden sollen (ein Backup spezieller Dateigruppen). Die ersten angegebenen Dateien werden immer in der primären Dateigruppen verwaltet. In dieser Dateigruppe werden die Systemtabellen der Datenbank angelegt. Per Voreinstellung ist die primäre Dateigruppe auch die Default-Dateigruppe, in der neue Tabellen und Indizes angelegt werden, wenn bei deren Anlage derselben keine Dateigruppe angegeben wird. Sie können mit der ALTER DATABASEAnweisung eine andere Dateigruppe zur Default-Dateigruppe machen. 5 # Im Register TRANSAKTIONSPROTOKOLL können Sie die gleichen Einstellungen für das Transaktionsprotokoll der Datenbank vornehmen, wie für die Datenbank. Das Transaktionsprotokoll sollte aus Performancegründen auf einer anderen Festplatte angelegt werden als die Datenbank. + ) $6 , Wenn Sie Festplatten in RAID-Systemen zusammengefasst haben, sollten Sie beachten, dass die Datenbankdateien auf einem RAID 0 oder RAID 0+1 oder idealerweise auf einem RAID 5-Set installiert werden sollte. Die in diesen Sets enthaltene parallele Verwendung von mehreren Platten erhöht die Performance erheblich. Das Transaktionsprotokoll dagegen sollte lediglich auf einem RAID 1-Set erstellt werden. Aufgrund der sequentiellen Struktur des Erzeugen und Bearbeiten von Datenbanken 30 Transaktionsprotokolls würde die parallele (und damit aufgeteilte) Speicherung der Daten einen Performanceverlust mit sich bringen. Ein RAID 1-Set erhöht jedoch auf jeden Fall die Sicherheit der Daten für den Fall eines Ausfalls einer oder mehrerer Festplatten. # Nach der Erstellung der Datenbank können Sie die bei der Erstellung eingestellten Optionen und weitere Optionen der Datenbank über die Eigenschaften derselben einstellen (über den Befehl EIGENSCHAFTEN im Kontextmenü der Datenbank). Abbildung 19: Die Optionen einer Datenbank Erzeugen und Bearbeiten von Datenbanken 31 Option ZUGRIFF EINSCHRÄNKEN Bedeutung MITGLIEDER VON 'DB_OWNER', 'DBCREATOR' ODER 'SYSADMIN': Wenn diese Option eingeschaltet ist können nur der Besitzer der Datenbank (der Database Owner, der Login, der die Datenbank erstellt hat), Mitglieder der speziellen Rolle dbcreator (Benutzer, die Datenbanken erzeugen dürfen) und Mitglieder der Rolls sysadmin (Systemadministratoren) die Datenbank verwenden. Diese Option wird oft verwendet, wenn Wartungsarbeiten oder Strukturänderungen an der Datenbank vorgenommen werden müssen und andere Benutzer von der Verwendung der Datenbank ausgeschlossen werden sollen. Im Gegensatz zur Option EINZELBENUTZERMODUS kann der DBO auch von mehreren unterschiedlichen Computern aus auf die Datenbank zugreifen. EINZELBENUTZERMODUS: Mit dieser Option kann nur ein Benutzer gleichzeitig auf die Datenbank zugreifen. Damit verhindern Sie, dass andere Benutzer mit der Datenbank arbeiten, während Sie Änderungen an der Struktur oder an den Optionen vornehmen. SCHREIBGESCHÜTZT Diese Option legt fest, dass die Daten grundsätzlich nur gelesen werden können. WIEDERHERSTELLUNG - Mit dieser Option definieren Sie, wie der SQL Server das MODELL Transaktionsprotokoll bezogen auf Backups verwaltet. Damit legen Sie fest, bis zu welchem Zeitpunkt eine Datenbank wiederhergestellt werden kann, nachdem diese z. B. aufgrund eines Stromausfalls beschädigt wurde. EINFACH: Das einfache Modell sorgt dafür, dass der SQL Server das Transaktionsprotokoll bei einem Prüfpunkt abschneidet. Dabei wird der Speicherplatz der Transaktionen, die bereits in die Datenbank geschrieben wurden, freigegeben. Da das Transaktionsprotokoll beim einfachen Modell nur die aktiven Transaktionen beinhaltet, bringt das Backup dieses Protokolls nichts und wird deswegen auch nicht ermöglicht. Sie können im einfachen Modell lediglich ein Backup und Restore der Datenbankdateien (vollständig und differentiell) ausführen, nicht des Transaktionsprotokolls. Tritt ein Fehler nach einem Backup auf, sind alle Änderungen zwischen dem Backup und dem Fehlerzeitpunkt verloren. Das einfache Modell bringt den »Vorteil«, dass das Transaktionsprotokoll nicht sehr groß werden kann. Der Nachteil ist, dass Sie erweiterte Backup-Strategien, die das Transaktionsprotokoll mit einbeziehen, nicht anwenden können. VOLLSTÄNDIG: Dieses Modell belässt alle Transaktionen im Transaktionsprotokoll bis dieses oder die Datenbank gesichert wird (erst dann werden die inaktiven Transaktionen abgeschnitten). Es ermöglicht damit ein Sichern der Datenbank (vollständig und differentiell) und ein separates Sichern des Transaktionsprotokolls. Dieses für die meisten größeren Datenbanken sinnvolle Modell erlaubt z. B. das Sichern der gesamten Datenbank jeden Tag um 00:00 und das Sichern des (kleineren und damit schneller gesicherten) Transaktionsprotokolls in den Betriebspausen. Damit ist die Wahrscheinlichkeit sehr gering, dass bei einem Crash des Servers viele Änderungen verloren gehen. MASSENPROTOKOLLIERT: Dieses dem vollständigen Modell ähnliche Erzeugen und Bearbeiten von Datenbanken 32 Modell führt dazu, dass bestimmte Massenänderungen an den Daten (z. B. über SELECT INTO) nur minimal protokolliert werden. Damit werden diese Massenoperationen zwar performanter ausgeführt und benötigen weniger Speicherplatz im Transaktionsprotokoll. Beim einem Crash ist die Gefahr des Datenverlustes bezogen auf die in den Massenoperationen veränderten Daten aber sehr groß. ANSI NULL IST STANDARD Mit dieser Option können Sie festlegen, ob Tabellenspalten mit der Einschränkung NULL oder NOT NULL definiert werden wenn bei der Erzeugung der Spalte weder NULL noch NOT NULL angegeben wird. REKURSIVE TRIGGER Normalerweise rufen Änderungen an Daten, die durch einen Trigger vorgenommen werden, keinen weiteren Trigger auf, der auf den vom ersten Trigger geänderten Tabellen definiert ist. Wenn Sie diese Option einschalten, ist der rekursive Aufruf von Triggern möglich. Sie müssen dabei aufpassen, dass, wenn ein Trigger dieselbe Tabelle ändert, die den Aufruf des Triggers bewirkt hat, derselbe Trigger zunächst unendlich oft rekursiv aufgerufen wird (wobei der SQL Server die Aufrufebenen auf 32 begrenzt). STATISTIKEN Statistiken sind Informationen über die Verteilung der Werte von Spalten in einer Tabelle. Der SQL Server verwendet diese Statistiken zur Optimierung von komplexen Abfragen (mit Joins). Er erkennt daraus, welche Tabelle vor welcher anderen abgefragt werden muss, damit die Abfrage möglichst performant ausgeführt wird. (Spezielle) Statistiken können Sie von Hand erstellen. Sinnvoll ist aber immer, dass Sie die Optionen zum automatischen Erstellen und Aktualisieren eingeschaltet lassen, damit der SQL Server die Default-Statistiken automatisch erzeugt und aktualisiert. Default-Statistiken werden für alle Spalten erzeugt, die der WHERE-Klausel einer Abfrage vorkommen. AUTOMATISCH ERSTELLEN STATISTIKEN AUTOMATISCH AKTUALISIEREN ERKENNUNG VON ZERISSENEN SEITEN Wenn Sie diese Option einstellen, erkennt der SQL Server so genannte zerrissene Seiten. Wie ich bereits erläutert habe, verwaltet der SQL Server alle Daten auf so genannten Seiten, die jeweils 8 KB groß sind. Windows verwaltet Daten hingegen normalerweise auf 512-KBSeiten. Wenn der SQL Server eine Seite speichert, muss Windows diese in mehrere System-Seiten splitten. Der SQL Server nimmt bereits nach dem Speichern der ersten System-Seite an, dass die gesamte SQL-Server-Seite erfolgreich gespeichert wurde. Fällt vor dem Speichern der letzten System-Seite allerdings das System aus, ist die SQL-Server-Seite nicht komplett gespeichert. Normalerweise erkennt der SQL Server beim späteren Einlesen der Seite (beim Recovering) nicht, dass die Seite nun zerrissen ist. Zerrissene Seiten können die gesamte Datenbank korrumpieren. Lassen Sie diese Option also eingeschaltet, damit der SQL Server zerrissene Seiten erkennt und beim Einlesen einen Fehler meldet (der weitere Zerstörungen verhindert). Das Erkennen zerrissener Seiten kostet lediglich ein wenig Prozessorzeit, weswegen es nur auf sehr ausgelasteten Systemen notwendig ist, darauf zu verzichten. Erzeugen und Bearbeiten von Datenbanken 33 AUTOMATISCH SCHLIEßEN AUTOMATISCH VERKLEINERN BEZEICHNER IN ANFÜHRUNGSZEICHEN VERWENDEN Mit dieser Option, die nur in der Personal Edition zur Verfügung steht, können Sie festlegen, dass der SQL Server die Datenbank automatisch herunterfährt wenn kein Benutzer mehr mit dieser verbunden ist. Da dann auch der Cache geleert wird, reduzieren Sie den Speicherbedarf des SQL Servers, was bei einer Verwendung auf einem Desktop-PC sinnvoll sein kann. Beim erneuten Abfragen dieser Datenbank muss der Cache allerdings zunächst wieder aufgebaut werden, was dann recht viel Zeit in Anspruch nimmt. Bei Datenbanken, bei denen im Betrieb viele Daten gelöscht werden, macht es u. U. Sinn, diese zu verkleinern. Dieses Verkleinern können Sie über spezielle SQL-Anweisungen ausführen (DBCC SHRINKDATABASE oder DBCC SHRINKFILE). Die per Voreinstellung ausgeschaltete Option AUTOMATISCH VERKLEINERN ermöglicht das automatische Verkleinern. In diesem Fall überprüft der SQL Server aber alle 30 Minuten, ob die Datenbank verkleinert werden kann. Dieses Überprüfen kostet natürlich Zeit und Performance. Lassen Sie diese Option also ausgeschaltet und verkleinern Sie die Datenbank bei Bedarf regelmäßig automatisch über einen als SQL-Server-Agent-Job ausgeführten DBCC-Befehl. Wenn Sie diese Option einschalten, hält der SQL Server die ANSISQL-Regeln für Anführungszeichen ein. Danach dürfen Zeichenketten nur in einfache Apostrophe eingeschlossen werden. Anführungszeichen dürfen dann nur verwendet werden, um Bezeichner, die Sonder- und Leerzeichen enthalten, einzuschließen (Beispiel: SELECT "Product Name" FROM "Sale Products"). Ist diese Option ausgeschaltet, können Sie Anführungszeichen auch für Zeichenketten verwenden (Beispiel: SELECT * FROM Customers WHERE City = "Berlin"). Bezeichner mit Sonderzeichen setzen Sie dann einfach in eckige Klammern. Tabelle 5: Die Datenbankoptionen Erzeugen und Bearbeiten von Datenbanken 34 9" $- Wenn Sie Datenbanken mit SQL erzeugen wollen, verwenden Sie die CREATE DATABASEAnweisung: CREATE DATABASE Datenbankname [ON [Dateispezifikation [,...n]] [,Dateigruppe [,...n]] ] [LOG ON Dateispezifikation [,...n]] [COLLATE Sortierungsname] [FOR LOAD | FOR ATTACH] Mit ON legen Sie fest, in welcher Datei bzw. in welchen Dateien die Datenbank angelegt wird. Das Argument Dateispezifikation bezieht sich auf die folgenden Angaben, die pro Datei notwendig sind: [PRIMARY] ( NAME = Logischer_Dateiname [, FILENAME = 'Dateiname'] [, SIZE = Größe] [, MAXSIZE = {Maximale_Größe | UNLIMITED}] [, FILEGROWTH = Größen_Inkrement]) Wenn Sie mehrere Dateien für eine Datenbank anlegen wollen, müssen Sie eine Datei über PRIMARY als primäre Datei angeben. Die primäre Datei enthält die Systemtabellen der Datenbank. Wenn Sie PRIMARY nicht angeben, wird die erste Datei zur primären Datei. Das Argument Dateigruppe bezieht sich auf Angaben, die für Dateigruppen notwendig sind: FILEGROUP Dateigruppen_Name Dateispezifikation [,...n] Für jede Datei müssen sie den physikalischen Dateinamen im Argument FILENAME und den logischen Dateinamen im Argument NAME angeben. Der logische Dateiname muss nicht angegeben werden, wenn Sie eine Datenbank mit FOR ATTACH aus bereits vorhandenen Dateien zusammensetzen. Dieser Dateiname wird in der SQL-Anweisung angegeben, wenn diese sich auf die Datei bezieht (wie z. B. ALTER DATABASE). Der logische Dateiname muss innerhalb der Datenbank eindeutig sein. Das Argument SIZE steuert die Anfangsgröße der Datei. Wird SIZE nicht angegeben, verwendet der SQL Server für die primäre Datei die Größe der model-Datenbank5 und für alle weiteren Dateien eine Größe von ein MB. MAXSIZE bestimmt, wie groß die Datei automatisch wachsen kann. Geben Sie dieses Argument nicht an, oder geben Sie hier UNLIMITED an, kann die Datei bis zu einer (theoretisch) unendlichen Größe wachsen. Geben Sie den Suffix KB oder MB an, um die maximale Dateigröße festzulegen. Das Argument FILEGROWTH bestimmt, wie die Datei vergrößert wird. Sie können hier einen Wert in KB, MB oder in % angeben. Wenn Sie den Wert 0 angeben, wird die Datei nicht automatisch vergrößert. Normalerweise legen Sie eine SQL Server-Datenbank mit einer Anfangsgröße von einem MB pro Datei an und ermöglichen das automatische Wachsen in %Schritten (z. B. 15%). Dadurch wird gewährleistet, dass die Datenbank nach einer anfänglichen Initialisierungsphase im späteren Betrieb nicht allzu häufig vergrößert werden muss. Das automatische Wachsen der Dateien verhindert massive Probleme, die entstehen, wenn der freie Platz in der Datenbank bzw. im Transaktionsprotokoll zu klein ist. 5 die model-Datenbank dient beim SQL Server als Vorlage für neu angelegte Datenbanken Erzeugen und Bearbeiten von Datenbanken 35 Das Argument LOG ON steuert, in welchen Dateien das Transaktionsprotokoll6 der Datenbank angelegt wird. Über COLLATE können Sie die Standardsortierung der Datenbank angeben, wenn Sie eine andere als die Standardsortierung des SQL Servers verwenden wollen (hauptsächlich für internationale Datenbanken). Sie können hier einen Windows- oder SQL-Sortierungsnamen angeben. Die entsprechenden Namen sind in der TSQL-Referenz beschrieben. Die entsprechenden Seiten finden Sie im Inhaltsverzeichnis über INSTALLIEREN VON SQL SERVER / SORTIERUNGSOPTIONEN FÜR INTERNATIONALE UNTERSTÜTZUNG. FOR LOAD existiert nur noch aus Kompatibilitätsgründen zum SQL Server 6.5. Mit FOR ATTACH können Sie eine Datenbank aus bereits vorhandenen Dateien aufbauen. Dieses Argument benötigen Sie immer dann, wenn Sie Datenbanken mit mehr als 16 Dateien aufbauen wollen, da CREATE DATABASE in einem Schritt nur maximal 16 Dateien zulässt. Im einfachsten Fall (ohne eine Datenbank in mehrere Dateien aufzusplitten), sieht die SQLAnweisung z. B. folgendermaßen aus: CREATE DATABASE Test ON ( NAME=Test_Data, FILENAME='c:\Data\Test_Data.mdf', SIZE=10MB, FILEGROWTH=20%) LOG ON ( NAME=Test_Log, FILENAME='c:\Logs\Test_Log.ldf', SIZE=1MB, FILEGROWTH=10%) Wenn die Datenbank in mehrere Dateien aufgesplittet werden soll, sieht die SQL-Anweisung z. B. folgendermaßen aus: CREATE DATABASE Test ON PRIMARY ( NAME=Test_Data_1, FILENAME='c:\Data\Test_Data_1.mdf', SIZE=10MB, FILEGROWTH=20%), ( NAME=Test_Data_2, FILENAME='d:\Data\Test_Data_2.mdf', SIZE=10MB, FILEGROWTH=20%) LOG ON ( NAME=Test_Log, FILENAME='e:\Logs\Test_Log.ldf', SIZE=1MB, FILEGROWTH=10%) Durch das Schlüsselwort PRIMARY wird die erste Datenbankdatei als die primäre Datei definiert. Die Anweisung kann noch komplexer werden, wenn Sie Datenbankdateien in Dateigruppen anlegen. Für entsprechende Beispiele verweise ich auf die TSQL-Hilfe zur CREATE DATABASEAnweisung. 6 Das Transaktionsprotokoll wird im Skript „Microsoft SQL-Server“ erläutert. Erzeugen und Bearbeiten von Datenbanken 36 : * % : 5 5 # Mit dem Enterprise Manager ist das Erstellen von Tabellen in einer Datenbank sehr einfach. Wählen Sie dazu den Befehl NEUE TABELLE im Kontextmenü des TABELLEN-Ordners im Ordner der Datenbank. Nachdem Sie den Namen der neuen Tabelle eingegeben haben, erscheint der Dialog zur Einrichtung der Tabelle. Abbildung 20: Dialog zum Einrichten von Tabellen Geben Sie idealerweise einen Spaltennamen an, der der SQL-Konvention entspricht (nur Buchstaben, Zahlen, der Unterstrich, # und &; das erste Zeichen muss ein Buchstabe sein). Im SQL Server können Sie aber auch Spaltennamen verwenden, die Sonderzeichen (Leerzeichen, Bindestriche etc.) enthalten. Abgesehen davon, dass Sie diese Bezeichner später in Abfragen in eckigen Klammern angeben müssen, führen solche Bezeichner bei eventuellen Übertragungen einer SQL-Server-Datenbank in andere Datenbanksysteme (z. B. Oracle), die Sonderzeichen nicht erlauben, zu Problemen. Daneben können Sie einstellen, ob Null-Werte in der Spalte erlaubt sind oder nicht. Nur Spalten, die keine Nullwerte enthalten dürfen, können als Primärschlüssel definiert werden. Beachten Sie, dass der Umgang mit NULL-Werten in Client-Anwendungen häufig einen großen Aufwand erfordert, da diese für Spalten, die NULL-Werte erlauben vor dem Lesen immer zuerst abfragen muss, ob die Spalten NULL enthält. Verwenden Sie die Option NULL ZULASSEN also mit Bedacht. In der Option STANDARDWERT geben Sie einen Wert ein, der standardmäßig für neue Datensätze in dieses Datenfeld geschrieben werden soll. Erzeugen und Verwalten von Tabellen 37 : 6# Bei der Definition von Spalten können Sie die folgenden Datentypen verwenden: Datentyp Größe (Byte) Beschreibung char[(n)] 0-8000 ASCII-Zeichenketten festgelegter Größe. In char-Spalten, die keine Null-Werte erlauben, werden Zeichenketten nach rechts mit Leerzeichen aufgefüllt, die u. U. bei der Bearbeitung abgeschnitten werden müssen. Werden Zeichenketten eingegeben, die größer sind als der Maximalwert, so schneidet der Server die Zeichen nach rechts einfach ab. Sie können bis zu 8000 Zeichen in diesem Datentyp speichern. nchar[(n)] 0-8000 nchar wird wie char verwendet, speichert jedoch varchar[(n)] 0-8000 varchar speichert wie char ASCII-Zeichenketten. Für varchar-Zeichenketten geben Sie zwar auch die Unicode-Zeichen, weswegen nur 4000 Zeichen möglich sind. Maximalgröße an, der Server speichert jedoch nur die tatsächlich eingegebenen Zeichen. Werden Zeichenketten eingegeben, die größer sind als der Maximalwert, so schneidet der Server die Zeichen nach rechts ab. nvarchar[(n)] 0-8000 nvarchar wird wie varchar verwendet, speichert jedoch datetime 8 Datumswerte zwischen dem 1.1.1753 und dem 31.12.9999. Wenn bei der Eingabe die Zeit weggelassen wird, wird der Wert 00:00:00 verwendet, wird das Datum weggelassen, wird der 01.01.1900 eingetragen. smalldatetime 4 Speichert Datumswerte zwischen dem 01.01.1900 und dem 06.06.2079 mit einer Genauigkeit von einer Minute. Wenn Sie erreichen wollen, dass Ihre Software noch nach dem 06.06.2079 korrekt läuft, verwenden Sie diesen Datentyp besser nicht (denken Sie an das Jahr 2000-Problem). bigint 8 Ganze Zahlen zwischen -263 (-9.223.372.036.854.775.808) und 263-1 (9.223.372.036.854.775.807) int 4 Ganze Zahlen +2.147.483.647 smallint 2 Ganze Zahlen zwischen -32.768 bis +32.767 tinyint 1 Ganze Zahlen zwischen 0 und 255 Unicode-Zeichen. zwischen -2.147.483.648 und Erzeugen und Verwalten von Tabellen 38 decimal[(p [, s])] numeric[(p [, s])] 1-17 je nach Zahlen mit fester Dezimalstelle zwischen -1038 und 1038-1 Genauigkeit mit einer Genauigkeit von 1 bis 38 Ziffern. p (Precision) gibt an, wie viele Ziffern links und rechts vom Komma insgesamt gespeichert werden können, s (Scale) gibt die Anzahl der Ziffern rechts vom Komma an. s und muss ein Wert zwischen 0 und p sein. Wenn Sie s nicht angeben, verwendet der SQL Server den Wert 0; für p wird standardmäßig 16 eingesetzt. SQL/92 definiert zwar einen Unterschied zwischen decimal und numeric (bei decimal müssen mindestens s Dezimalstellen vorhanden sein, bei numeric muss die Anzahl der angegebenen Dezimalstellen genau sein), der SQL Server macht dagegen keinen Unterschied. float[(n)] 8 Zahlen mit fließender Dezimalstelle. n gibt die Genauigkeit mit einem Wert von 1 bis 53 an. Geben Sie eine Genauigkeit von 24 an, so besitzt dieser Typ dieselbe Bedeutung wie real. Standardmäßig wird eine Genauigkeit von 15 verwendet. Damit können Zahlen zwischen -1.79 * 10308 und 1.79 * 10308 gespeichert werden. Bei einer Genauigkeit von 1-24 werden sieben Dezimalstellen verwaltet, bei einer Genauigkeit von 25 bis 53 dagegen 15. real 4 real steht im SQL Server für float(24). money 8 Dezimalzahl mit vier festen Dezimalstellen zwischen 922.337.203.685.477,5808 und +922.337.203.685.477,5807. money wird für Währungen verwendet, da diese üblicherweise mit vier Dezimalstellen gerechnet werden. Berechnungen mit festen Dezimalstellen sind schneller als solche mit dynamischen und vermeiden Rundungsfehler, die durch die eingeschränkte Genauigkeit der anderen Datentypen entstehen. smallmoney 4 Währungsbeträge +214.748,3647 text n Seiten zu Dynamische Zeichenketten bis 2.147.483.647 Zeichen je 8 KB ntext n Seiten zu ntext speichert wie text dynamische Zeichenketten, je 8 KB allerdings als Unicode-Zeichen. Deswegen können auch nur 1.073.741.823 Zeichen gespeichert werden. image n Seiten zu image speichert binäre Daten (Dateien, Objekte) bis zu je 8 KB 2.147.483.647 Byte Größe. image wird häufig zur Speicherung von binären Objekten, wie z. B. MicrosoftWord-Dokumenten verwendet. binary 0-8000 Dieser Datentyp speichert binäre Daten mit einer maximalen Länge von 8000 Byte. varbinary 0-8000 varbinary speichert wie binary binäre Daten. Der zwischen -214.748,3648 und Server verwaltet jedoch nur soviel Speicherplatz, wie die tatsächlich eingegebenen Daten benötigen, und nicht wie bei binary immer die eingestellte Größe. Erzeugen und Verwalten von Tabellen 39 1 bit speichert boolesche Werte in Form von 0 oder 1. timestamp 8 Ein timestamp-Feld wird bei jedem Hinzufügen oder Ändern eines Datensatzes automatisch mit einem über die gesamte Tabelle eindeutigen Wert (der aus der Systemzeit generiert wird) belegt. Solche Felder benötigen Sie immer dann (und eigentlich auch nur dann), wenn Tabellen in mehreren Datenbanken repliziert werden sollen. Der SQL Server erkennt beim Synchronisieren der einzelnen Datenbanken am timestamp-Feld, ob ein Datensatz verändert wurde. Die Speicherung entspricht der eines varbinary(8)-Feldes. Sie können nur ein timestampFeld pro Tabelle generieren. uniqueidentifier 16 Dieser Datentyp dient der Speicherung einer GUID (Global Unique Identifier). Eine GUID ist ein 16-Bit Hexadezimalwert, der über die gesamte Welt eindeutig ist. In TSQL kann eine GUID mit der NEWID-Funktion erzeugt werden. GUIDs werden häufig zur Benennung und Identifikation von Objekten verwendet. sysname 256 sysname ist ein benutzerdefinierter Datentyp, der als nvarchar(128) definiert ist. Nullwerte werden nicht bit Integerwerte können eingegeben werden, werden jedoch als 1 gewertet. erlaubt. Dieser Datentyp wird vom SQL Server in Systemtabellen verwendet. cursor Dieser Datentyp verweist auf einen Cursor. Ein Cursor wird eigentlich nur innerhalb von Stored Procedures, Triggern und Funktionen eingesetzt, um eine Tabelle oder Abfrage sequenziell durchlaufen zu können (was nur selten notwendig ist). table Dieser Datentyp wird hauptsächlich innerhalb von Stored Procedures verwendet, um das Ergebnis einer Abfrage temporär zwischenzuspeichern (ähnlich einem Recordset bei ADO oder einem ResultSet bei JDBC). sql_variant Dieser Datentyp ermöglicht das Speichern verschiedener Datentypen in einem Feld, ähnlich dem Datentyp Variant in Visual Basic. Tabelle 6: Die Datentypen des SQL Servers : " 4 , ) 6& Der Primärschlüssel einer Tabelle wird über einen Primary Key Constraint (eine Primärschlüssel-Einschränkung) definiert und dient der eindeutigen Identifizierung einzelner Datensätze und der Herstellung von Beziehung zwischen Tabellen. Ein Primärschlüssel besteht in der Regel aus einer Spalte, kann jedoch auch aus mehreren Spalten zusammengesetzt sein. Die in die betreffenden Felder eingegebenen Daten müssen über die gesamte Tabelle eindeutig sein. Wenn Sie der Tabelle einen Primärschlüssel hinzufügen wollen, markieren Sie die Felder, die den Primärschlüssel definieren (durch einen Klick auf das graue Kästchen links, wenn Sie mehrere Spalten markieren wollen, halten Sie die STRG-Taste beim Klicken gedrückt) und betätigen das Schlüssel-Symbol in der Symbolleiste. Für einen Primary Key Constraint erzeugt Erzeugen und Verwalten von Tabellen 40 der SQL Server intern einen eindeutigen (Unique-) Index. Die Spalten des Primärschlüssel brauchen (und sollten7) Sie also nicht explizit mit einem Index versehen, um die Suche oder das Sortieren in diesen Spalten zu beschleunigen. Per Default wird der Index des Primärschlüssels als Clustered Index (gruppierter Index) erstellt. Wenn in Abfragen die Felder eines gruppierten Index in WHERE-, ORDER BY-, oder GROUP BYKlauseln verwendet werden, werden diese Abfragen wesentlich schneller ausgeführt, als wenn der Index nicht gruppiert ist. Das liegt daran, dass ein gruppierter Index nicht ein Index im klassischen Sinn ist, sondern dafür sorgt, dass die Datenseiten der Tabelle in einem balancierten Baum (B-Baum) gespeichert werden, dessen Schlüssel die im Index enthaltenen Spalten sind. Bei klassischen Indizes werden in einem B-Baum lediglich die Datensatznummern der Datensätze gespeichert. Eine Tabelle kann nur einen gruppierten Index enthalten und sollte, wenn Spalten indiziert sind, aus Performancegründen immer einen gruppierten Index enthalten. Sie können, wenn Sie einen anderen Index als gruppierten Index verwenden wollen, auch die Clustered-Option für den Index des Primärschlüssels abschalten. Eine Identitätsspalte (Identity-Column) ist eine Spalte, die einen numerischen Datentyp besitzen muss und vom Server bei jedem neuen Datensatz um einen einzustellenden Wert inkrementiert wird. Sie können für die Identitätsspalte nur Spalten auswählen, die numerisch sind, keine Nullwerte zulassen und keinen Defaultwert besitzen. Die Identitätsspalte kann mit der Spalte für den Primärschlüssel identisch sein. Der Eintrag in der Option ID-STARTWERT spezifiziert den Anfangswert für neue Datensätze. ID-SCHRITTWEITE definiert den Wert mit dem für jeden neuen Datensatz inkrementiert wird. : / + %0;) Die Option IST ROWGUID besagt, dass die Spalte eine Spalte ist, die einen GUID8-Wert speichern soll, der einen Datensatz ein-eindeutig identifizieren soll. GUID-Werte sind hexadezimale Werte (wie z. B. der Wert BA2DE025-8467-11D3-9E43-00400548C419), die per „intelligentem“ Zufallsgenerator mit Hilfe des aktuellen Datums, der Zeit, der ID der Netzwerkkarte und aktuellen Registerinhalten erzeugt werden und die über die gesamte Welt (bzw. über das gesamte Universum) eindeutig sind. GUIDs werden üblicherweise zur Identifizierung gespeicherter Objekte verwendet. Mit GUIDs können Sie auch viele Probleme umgehen, die bei Identitätsspalten auftreten können, wenn mehrere Benutzer gleichzeitig neuen Datensätze anlegen. Der SQL Server nutzt GUID-Spalten außerdem bei Replikationen. Eine GUID-Spalte muss den Datentyp uniqueidentifier besitzen und sollte als Defaultwert die Funktion NEWID() zugewiesen bekommen, die einen neuen GUID-Wert erzeugt. : 8 ) ; < & Indizes beschleunigen Abfragen, wenn die im Index enthaltenen Felder in WHERE-, ORDER BY-, oder GROUP BY-Klauseln verwendet werden oder wenn mit anderen Techniken (z. B. mit der Find-Methode in ADO) in diesen Spalten suchen. Ein Index wird in einem balancierten Baum gespeichert. Der SQL Server speichert für normale (keine Clustered-) Indizes für jeden Datensatz ein Blatt im Baum mit dem/den Schlüsselwert(en) und einem Verweis auf den 7 Wenn Sie die Spalten eines Primärschlüssels mit einem zusätzlichen Index versehen, muss dieser Index bei Aktualisierungen der Tabelle ebenfalls aktualisiert werden, was die Aktualisierung unnötig verlangsamt. 8 Global Unique Identifier Erzeugen und Verwalten von Tabellen 41 Datensatz. Die Suche in einem balancierten Baum ist wesentlich schneller als die sequentielle Suche in den Datensätzen, die ohne Index notwendig ist. Indizes erzeugen Sie über die Eigenschaften der Tabelle, die über das erste Symbol von rechts in der Symbolleiste erreichbar ist. Wählen Sie das Register INDIZES / SCHLÜSSEL. Abbildung 21: Register zur Definition von Indizes in den Tabelleneigenschaften mit einem auf den Nachnamen des Kunden gesetzten Index Wählen Sie den Schalter NEU um einen neuen Index zu erstellen. Geben Sie danach im Feld INDEXNAME einen sinnvollen Namen für den neuen Index an und wählen Sie die Spalten, die im Index verwaltet werden sollen. Erzeugen und Verwalten von Tabellen 42 Das korrekte Erstellen von Indizes ist keine einfache Aufgabe. Indizieren Sie zunächst nur die Felder, die später häufiger in WHERE- ORDER BY- oder GROUP BY-Klauseln verwendet werden. Zusätzlich sollten Sie normalerweise auch die Felder indizieren, die mit den Primärschlüsselfeldern anderer Tabellen in Beziehung gesetzt und die in Abfragen häufiger über Joins mit diesen in Beziehung gesetzt werden sollen. Setzen Sie jedoch nicht zu viele Indizes, da diese bei jedem Hinzufügen, Ändern oder Löschen von Daten aktualisiert werden müssen, was u. U. recht viel Zeit in Anspruch nehmen kann. Zusammengesetzte Indizes machen dann Sinn, wenn später häufiger mehrere Spalten der Tabelle in einer definierten Reihenfolge in WHERE- ORDER BY- oder GROUP BY-Klauseln verwendet werden. Wichtig zu wissen dabei ist, dass der SQL Server immer auch die erste Spalte eines zusammengesetzten Index als normale Indexspalte verwenden kann um Abfragen zu optimieren, die sich nur auf diese Spalte beziehen. Eine sehr gute Hilfe beim Ermitteln der optimalen Indizes der Enterprise-Manager-Indexoptimierer, den ich in diesem Artikel allerdings nicht beschreibe. ; < ) & ' , 4 ( ; < Ein Unique Constraint und ein Unique Index ähnelt einem Primärschlüssel: die betreffenden Felder sind eindeutig indiziert und erlauben damit keine doppelten Werte. Unique Constraints/Indizes werden dazu verwendet, die Datenintegrität zu wahren und Beziehungen zwischen Tabellen herzustellen wenn der Primärschlüssel dafür nicht geeignet ist bzw. nicht vorhanden ist oder bereits verwendet wird. Der Unterschied zwischen einem Unique Constraint und einem Unique Index ist mir nicht klar geworden, da ein Unique Constraint genau wie ein Unique Index (wohl aber intern) indiziert ist und damit auch immer einen Performancegewinn bei Verwendung der betroffenen Felder in WHERE-, ORDER BY-, oder GROUP BY-Klauseln bringt. Möglicherweise hängt die Möglichkeit, einen Unique Constraint zu erzeugen mit der Tatsache zusammen, dass der derzeit gültige SQLStandard (SQL/92) keine Indizes kennt. Um einen Unique Constraint zu erstellen, wählen Sie die Option UNIQUE ERSTELLEN und EINSCHRÄNKUNG. Wollen Sie einen Unique Index erstellen, wählen Sie statt EINSCHRÄNKUNG eben INDEX. Die Option DOPPELTE SCHLÜSSEL IGNORIEREN gilt nur für eindeutige, gruppierte Indizes und steuert das Verhalten des SQL Servers beim Versuch, einen Datensatz mit einem Wert in der indizierten Spalte anzufügen, der bereits existiert. Schalten Sie diese Option ein, generiert der SQL Server beim Anfügen von Datensätzen mit doppelten Werten nur eine Warnmeldung, fügt diese Datensätze nicht an, führt jedoch die SQL-Anweisung weiter aus. Schalten Sie die Option ab, wird beim Anfügen solcher Datensätze ein Fehler generiert und die komplette SQLAnweisung zurückgesetzt. Erzeugen und Verwalten von Tabellen 43 Das folgende Beispiel erzeugt eine Tabelle mit einem eindeutigen gruppierten Index, der doppelte Schlüssel ignorieren soll (mit SQL ): /* Erstellen einer Tabelle, die die Werte speichern soll, die an die Testtabelle angefügt werden sollen */ CREATE TABLE Test_Values (Value int) /* Einfügen INSERT INTO INSERT INTO INSERT INTO der Testwerte */ Test_Values VALUES (10) Test_Values VALUES (11) Test_Values VALUES (10) /* Erstellen der Test-Tabelle */ CREATE TABLE Dup_Key_Test ( ID int IDENTITY, No_Dup_Key int ) /* Erstellen des gruppierten, eindeutigen Index auf der Test-Tabelle */ CREATE UNIQUE CLUSTERED INDEX IX_Dup_Key_Test ON Dup_Key_Test (No_Dup_Key) WITH IGNORE_DUP_KEY /* Einfügen doppelter Spalten */ INSERT INTO Dup_Key_Test (No_Dup_Key) SELECT Value FROM Test_Values Das Einfügen der Datensätze mit doppelten Werten führt in diesem Beispiel dazu, dass der SQL Server zwar die zwei eindeutigen Datensätze anfügt, für den doppelten Datensatz jedoch eine Warnmeldung ausgibt: Server: Nachr.-Nr. 3604, Schweregrad 16, Status 1, Zeile 20 Doppelter Schlüssel wurde ignoriert. Die Tabelle hat nach Ausführung dieses Beispiels die folgenden Datensätze gespeichert: ID ----------1 2 No_Dup_Key ----------10 11 (2 row(s) affected) Wenn Sie die Option IGNORE_DUP_KEY nicht angeben, wird bei dem Beispiel kein Datensatz angefügt: Server: Nachr.-Nr. 2601, Schweregrad 14, Status 3, Zeile 19 Zeile mit doppeltem Schlüssel kann in Objekt 'Dup_Key_Test' mit eindeutigem Index 'IX_Dup_Key_Test' nicht eingefügt werden. Die Anweisung wurde beendet. 2 Ein Index wird genau wie die Daten physikalisch auf Seiten von acht KB Größe gespeichert. Mit dem Füllfaktor können Sie bestimmen, wie viel Platz auf diesen Seiten bei der Neuorganisation der Seiten und beim ersten Erstellen des Index frei bleibt (ein Füllfaktor von 75% bewirkt, dass 25% frei bleiben). Ist der Füllfaktor auf 0 eingestellt, wird der DefaultFüllfaktor der Datenbank verwendet. Bei Änderungen der indizierten Spalten der Datensätze oder beim Anfügen von neuen Datensätzen muss immer auch der Index angepasst werden. Ist der Füllfaktor 100%, müssen dann u. U. einige oder auch alle Indexseiten umorganisiert werden, was natürlich recht viel Zeit kosten kann. Mit einem niedrigen Füllfaktor können Sie das Umorganisieren in den meisten Fällen vermeiden, da die Indexseiten ja noch Platz für neue Einträge besitzen. Ein niedriger Füllfaktor bewirkt allerdings auch, dass mehr Indexseiten vorhanden sind, was den benötigten Speicherplatz erhöht und zudem (was wesentlich wichtiger ist) die Performance bei Abfragen vermindert. Die korrekte Einstellung des Füllfaktors ist eine schwierige Feintuning-Arbeit und muss u. U. mit mehreren Tests ermittelt werden. Als Faustregel gilt: Ist die Anwendung Erzeugen und Verwalten von Tabellen 44 bezogen auf die betroffene Tabelle abfrageintensiv, sollte der Füllfaktor größer sein, ist die Anwendung transaktionsintensiv (viele Änderungen und Hinzufügen von Datensätzen), sollte der Füllfaktor kleiner sein. & ) ' ## ) ( Wenn in Abfragen die Felder eines gruppierten Index in WHERE-, ORDER BY-, oder GROUP BYKlauseln verwendet werden, werden diese Abfragen wesentlich schneller ausgeführt, als wenn der Index nicht gruppiert ist. Das liegt daran, dass ein gruppierter Index nicht ein Index im klassischen Sinn ist, sondern dafür sorgt, dass die Datenseiten der Tabelle in einem balancierten binären Baum (B-Baum) gespeichert werden, dessen Schlüssel die im Index enthaltenen Spalten sind. Bei klassischen Indizes werden in einem B-Baum lediglich die Datensatznummern der Datensätze gespeichert. Eine Tabelle kann nur einen gruppierten Index enthalten und sollte, wenn Spalten indiziert sind, aus Performancegründen immer einen gruppierten Index enthalten. Beachten Sie, dass per Default der Primärschlüssel aus einem gruppierten Index besteht. Sie können, wenn Sie einen anderen Index als gruppierten Index verwenden wollen, auch die Clustered-Option für den Index des Primärschlüssels abschalten. Die Option DOPPELTE SCHLÜSSEL IGNORIEREN ist nur relevant für nicht eindeutige Indizes. Wenn Sie diese Option einschalten, werden (lt. Delaney) Änderungen an den Daten, die mehrere Datensätze in der Tabelle betreffen, nicht komplett verworfen, wenn die Änderung eines Datensatzes einen doppelten Wert in der indizierten Spalte verursachen würde. Diese Änderungen werden dann einfach ignoriert. Normalerweise ist diese Option ausgeschaltet, womit die komplette SQL-Anweisung beim Auftreten eines Indexfehlers verworfen wird. Eine Tabelle ist z. B. folgendermaßen aufgebaut: ID Eindeutige_Spalte 1 a 2 b 3 c 4 d Ist die Eindeutige_Spalte eindeutig indiziert, führt die SQL Anweisung UPDATE Test SET Eindeutige_Spalte = 'x' WHERE ID IN (1, 2) bei ausgeschalteter Option zu einem Fehler, die Änderung wird nicht vorgenommen. Ist die Option eingeschaltet, sollte eigentlich der erste Datensatz aktualisiert und die Änderung beim zweiten Datensatz ignoriert werden. Leider funktionierte dies bei einem Test (wie so oft) auf meinem System nicht, der SQL Server ignorierte diese Option einfach. Die Hilfe zum SQL Server sagt leider zu dieser Option sehr wenig und nach meiner Meinung auch falsches aus. Die Option STATISTIKEN NICHT AUTOMATISCH NEU BERECHNEN bewirkt, dass die für Optimierungen intern verwendete Indexstatistik nicht neu berechnet werden soll. Diese Option sollten Sie nicht einschalten, da Sie damit die automatische Optimierung von Abfragen verschlechtern. & , , 4 Eine Check-Einschränkung (Check Constraint) ist eine Bedingung, die überprüft wird, wenn Datensätze der Tabelle geändert oder angefügt werden. Eine Check-Einschränkung könnte z. B. festlegen, dass die Kunden-Nummer nicht negativ sein darf. Bei Verletzungen der so definierten Regel wird der Datensatz nicht geändert bzw. angefügt und ein Fehler generiert. Erzeugen und Verwalten von Tabellen 45 Check-Einschränkungen können Sie lokal (nur innerhalb der Tabelle gültig) oder global (in allen Tabellen anwendbar) definieren. Lokale Check-Einschränkungen werden über das Register CHECK-EINSCHRÄNKUNGEN in den Tabelleneigenschaften erstellt, wobei Sie die SQL-Syntax für Bedingungen verwenden. Wählen Sie den Schalter NEU, um eine neue CheckEinschränkung zu erstellen. Abbildung 22: Register zur Definition von Check-Einschränkungen mit einer die Kunden-Nummer überprüfenden Einschränkung Die Check-Einschränkung erhält einen Bezeichner der per Konvention mit CK_ beginnen sollte. Verwenden Sie Ihnen selbst zuliebe Bezeichner, die einer bestimmten Konvention folgen, z. B. CK_ mit angehangenen Tabellen- und Feldnamen. Dies erleichtert Ihnen später die Fehlerauswertung in der Client-Anwendung, da Sie Fehler wie Server: Nachr.-Nr. 547, Schweregrad 16, Status 1, Zeile 1 Die INSERT-Anweisung verstieß gegen die COLUMN CHECK-Einschränkung 'CK_Kunden_Kunden_Nr'. Der Konflikt trat in der Fahrradverleih-Datenbank, Tabelle 'Kunden', column 'Kunden_Nr' auf. Die Anweisung wurde beendet. erhalten, die Sie für den Anwender erst noch übersetzen müssen. Wenn Sie dann nach „CK_“ suchen können, um den Feldnamen zu ermitteln, werden Sie sich freuen9. Eine Einschränkung kann sich auch auf mehrere Spalten beziehen. 9 Theoretisch könnten Sie auch im Fehlertext nach den '-Zeichen suchen, um den Spaltennamen zu erhalten. Ich würde mich jedoch nicht darauf verlasen, dass der Spaltenname in den verschiedenen Sprachen und den zu erwartenden neuen Versionen des SQL Servers immer an derselben Stelle steht. Erzeugen und Verwalten von Tabellen 46 Wenn Sie die Option EINSCHRÄNKUNG FÜR INSERT UND UPDATE ERZWINGEN ausschalten, wird die Einschränkung inaktiv. Diese Möglichkeit ist in Sonderfällen sinnvoll, nämlich dann, wenn Sie externe Daten importieren, die u. U. den definierten Regeln nicht entsprechen. Durch das Ausschalten der Einschränkungen können Sie die Daten importieren, danach in einen konsistenten Zustand versetzen (indem Sie die fehlerhaften Daten korrigieren) und schließlich wieder die Einschränkung aktivieren. Vorhandene Einschränkungen können Sie über die Liste anzeigen, bearbeiten und auch wieder über den LÖSCHEN-Schalter löschen. 0 & , , 4 Globale Check-Einschränkungen können Sie an Spalten in mehreren Tabellen binden und erleichtern sich somit die Pflege und Wartung global verwendbarer Regeln. Globale CheckEinschränkungen erstellen Sie im Enterprise-Manager über den Ordner REGELN im betreffenden Datenbankordner. Wählen Sie im Kontextmenü den Befehl NEUE REGEL. Abbildung 23: Der Dialog zur Einrichtung von globalen Regeln mit einer Regel, die eine Postleitzahl überprüfen soll Der Name beginnt wieder mit CK_. In der Einschränkung dürfen Sie keinen Spaltennamen verwenden, da die Einschränkung an beliebige Spalten gebunden werden kann. Verwenden Sie stattdessen Variablen, die Sie am Präfix @ erkennen. Über den Schalter SPALTEN BINDEN (der erst verfügbar ist, nachdem Sie die Regel gespeichert haben) wird die globale Einschränkung an Spalten aus verschiedenen Tabellen gebunden. Erzeugen und Verwalten von Tabellen 47 Abbildung 24: Der Dialog zur Binden von Regeln an Tabellenspalten Wenn ein eingegebener Wert den Einschränkungen nicht entspricht, lässt der SQL Server keine Änderung bzw. kein Anhängen von Datensätzen zu und erzeugt einen Fehler. Die folgende SQL-Anweisung: INSERT INTO Kunden (Kunden_Nr, Vorname, Nachname, Strasse, Plz, Ort, Telefon) VALUES (1001, 'Zaphod', 'Beeblebrox', 'Starway 1', 'X-1', 'Milchstrasse', '012345') erzeugt z. B. diesen Fehler: Server: Nachr.-Nr. 513, Schweregrad 16, Status 1, Zeile 1 Beim Einfügen oder Aktualisieren einer Spalte trat ein Konflikt mit einer Regel auf, die in einer vorherigen CREATE RULE-Anweisung festgelegt wurde. Die Anweisung wurde beendet. Der Konflikt trat in der FahrradverleihDatenbank, Kunden-Tabelle, Plz-Spalte auf. Die Anweisung wurde beendet. Erzeugen und Verwalten von Tabellen 48 :" % , ) 5 4 Wenn Sie zwischen Tabellen Beziehungen mit referentieller Integrität aufbauen wollen, können Sie prinzipiell zwischen zwei Varianten wählen: • Verwendung von DRI (Declared Referential Integrity), • Verwenden von Triggern. DRI verwenden Sie, wenn Sie in der Detailtabelle einen Fremdschlüssel (Foreign Key) aufbauen, der den Primärschlüssel oder ein mit einem Unique-Index indiziertes Feld der Mastertabelle referenziert. DRI besitzt gegenüber der Verwendung von Triggern mittlerweile nur noch Vorteile. Trigger waren in Vorversionen des SQL Servers notwendig um Beziehungen mit kaskadierenden Update- und Löschvorgängen zu ermöglichen (die nun auch automatisch möglich sind). Da Trigger für diese speziellen Beziehungen beim SQL Server 2000 nicht mehr notwendig sind und auch sehr komplex zu programmieren sind, verzichte ich in diesem Artikel auf eine weitere Beschreibung dieser Technik. Zur Herstellung einer Beziehung zwischen einer Master und einer Detailtabelle verwenden Sie im Enterprise Manager idealerweise ein Diagramm. Falls noch kein Diagramm besteht, erzeugen Sie (über das Kontextmenü des DIAGRAMME-Eintrags im Datenbank-Ordner) ein neues und fügen die betroffenen Tabellen hinzu. Abbildung 25: Erstellen eines neuen Diagramms Erzeugen und Verwalten von Tabellen 49 Abbildung 26: Diagramm zur Einrichtung von Tabellen und Beziehungen Ziehen Sie nun einfach das graue Kästchen neben dem Schlüsselfeld der Mastertabelle auf das graue Kästchen des Schlüsselfeld der Detailtabelle, in diesem Beispiel also z. B. das Feld Kunden_Nr aus der Tabelle Kunden auf das Feld Kunden_Nr aus Verträge. Im darauf folgenden Dialog stellen Sie die Beziehung ein. Erzeugen und Verwalten von Tabellen 50 Abbildung 27: Dialog zur Einrichtung der Beziehung Für jede Beziehung können Sie definieren, dass diese bei der Erstellung für bereits existierende Daten überprüft wird. Wenn bereits Daten gespeichert sind, die der Beziehung nicht entsprechen (z. B. Verträge mit einer nicht existierenden Kunden-Nummer), können Sie die Option VORHANDENE DATEN BEI ERSTELLUNG ÜBERPRÜFEN ausschalten. Beachten Sie dabei aber, dass Sie dann Daten besitzen, die nicht den allgemeinen Regeln der Datenbank entsprechen. Sie sollten diese Daten idealerweise vor der Erstellung der Beziehung in Ordnung bringen und diese Option eingeschaltet lassen. Die Option BEZIEHUNG FÜR REPLIKATION ERZWINGEN bezieht sich auf replizierte Datenbanken. Ohne diese Option können Sie Daten aus der Tabelle auch dann replizieren, wenn die entsprechenden Master-Datensätze dort nicht vorhanden sind. Wenn Sie die Option BEZIEHUNG FÜR INSERT- UND UPDATE-ANWEISUNGEN ERZWINGEN ausschalten, wird die Beziehung inaktiv. Diese Möglichkeit ist wie schon bei CheckEinschränkungen in Sonderfällen sinnvoll, wenn Sie externe Daten importieren, die u. U. den definierten Regeln nicht entsprechen. Durch das Ausschalten der Beziehung können Sie die Daten importieren, danach in einen konsistenten Zustand versetzen (indem Sie die fehlerhaften Daten korrigieren) und schließlich wieder die Einschränkung aktivieren. 1 =,% Ist die Option BEZIEHUNG FÜR INSERT- UND UPDATE-ANWEISUNGEN ERZWINGEN eingeschaltet, können Sie über die Unteroption VERKNÜPFTE FELDER MIT CASCADE AKTUALISIEREN festlegen, dass der SQL Server Änderungen an dem Wert eines verknüpften Primärschlüsselfeldes in der Mastertabelle automatisch an die Detailtabelle weitergibt. Ohne diese Option kann ein Primärschlüsselwert nicht geändert werden wenn dieser in einer Detailtabelle in einem Fremdschlüsselfeld gespeichert ist. Verwenden Sie diese Option immer dann, wenn Sie das Ändern des Primärschlüsselwertes in der Mastertabelle auch dann ermöglichen wollen, wenn bereits Datensätze in Beziehung stehen. Normalerweise sollten Sie diese Änderungen allerdings vermeiden, da Primärschlüsselwerte in Unternehmen häufig eine besondere Bedeutung besitzen und nicht änderbar sein sollen wenn diese bereits in Detailtabellen verwendet werden. Erzeugen und Verwalten von Tabellen 51 Die Option VERKNÜPFTE DATENSÄTZE MIT CASCADE LÖSCHEN ermöglicht das Löschen von Datensätzen aus der Mastertabelle auch dann, wenn die entsprechenden Primärschlüsselwerte in der Detailtabelle verwendet werden (was ohne diese Option nicht möglich ist). So können Sie z. B. eine Bestellung löschen womit automatisch alle bestellten Artikel gelöscht werden. Gehen Sie sehr vorsichtig mit dieser Option um. Wenn Sie diese Option z. B. in der Beziehung zwischen der Kunden- und der Verträge-Tabelle einschalten, werden automatisch alle Verträge eines Kunden gelöscht, wenn dieser Kunde gelöscht wird. In normalen Datenbanken ist solch ein Verhalten nicht erwünscht, da dabei in vielen Fällen Daten verloren gehen. Nachdem Sie die Beziehungen definiert haben, zeigt das Diagramm diese an, wobei jedoch die in Beziehung stehenden Felder korrekt dargestellt werden. Abbildung 28: Diagramm mit definierten Beziehungen Wenn Sie das Diagramm abspeichern, werden die Fremdschlüssel angelegt. In einem Diagramm können Sie auch die Spalten der Tabellen verändern. Eine 1:N-Beziehung realisieren Sie, indem Sie das Schlüsselfeld in der Detailtabelle nicht oder nicht eindeutig indizieren. Eine 1:1-Beziehung erstellen Sie, indem Sie das Schlüsselfeld in der Detailtabelle eindeutig indizieren. Wenn Sie zulassen, das in das Schlüsselfeld der Detailtabelle Nullwerte eingegeben werden können, muss kein Datensatz der Mastertabelle in Beziehung mit dem Datensatz der Detailtabelle stehen; der Anwender muss keinen Masterdatensatz auswählen. Da Sie die Nullwert-Einstellung nur bei einer neuen Tabelle editieren können, müssen Sie also beim Anlegen der Tabellen bereits wissen, wie die Beziehung genau aussehen soll. Erzeugen und Verwalten von Tabellen 52 Wenn Sie nun an die Detailtabelle einen Datensatz anfügen oder editieren wollen, für den kein Datensatz in der Mastertabelle existiert, erzeugt der Server einen Fehler folgender Form (Beispiel): Server: Nachr.-Nr. 547, Schweregrad 16, Status 1, Zeile 1 Die INSERT-Anweisung verstieß gegen die COLUMN FOREIGN KEY-Einschränkung 'FK_Verträge_Standorte'. Der Konflikt trat in der Fahrradverleih-Datenbank, Tabelle 'Standorte', column 'Standort_Nr' auf. Die Anweisung wurde beendet. Wenn Sie einen Datensatz in der Mastertabelle löschen oder das Schlüsselfeld ändern wollen, zu dem Datensätze in der Detailtabelle existieren, wird ein ähnlicher Fehler erzeugt (sofern die kaskadierende Aktualisierungs- bzw. Löschweitergabe nicht eingeschaltet ist): Server: Nachr.-Nr. 547, Schweregrad 16, Status 1, Zeile 1 Die DELETE-Anweisung verstieß gegen die COLUMN REFERENCE-Einschränkung 'FK_Fahrzeuge_Fahrzeugtypen'. Der Konflikt trat in der FahrradverleihDatenbank, Tabelle 'Fahrzeuge', column 'Fahrzeugtyp_Nr' auf. Die Anweisung wurde beendet. :/ 5 $- Das Erstellen von Tabellen mit SQL ist oft wesentlich einfacher als die Verwendung des Enterprise Managers (sofern Sie die SQL-Syntax kennen). Der SQL Server verwendet dazu eine recht komplexe Variante der CREATE TABLE-Anweisung: CREATE TABLE [{Datenbankname.[Besitzer]. | Besitzer.}]Tabellenname( {<Spaltendefinition> | Spaltenname AS Ausdruck für eine berechnete Spalte | <Tabelleneinschränkung>} [,...n] ) [ON {Dateigruppe | DEFAULT} ] [TEXTIMAGE_ON {Dateigruppe | DEFAULT} ] Im Unterschied zu SQL/92 kann hier bei der Erzeugung der Besitzer der Tabelle angegeben werden. Der Besitzer einer Tabelle besitzt immer alle Rechte auf dieser Tabelle. Per Voreinstellung ist immer der Benutzer, der die Tabelle anlegt, der Besitzer. Ein weiterer Unterschied ist, dass statt einer Spaltendefinition auch eine Berechnung für eine berechnete Spalte angegeben werden kann. Das folgende Beispiel erzeugt eine Artikeltabelle mit NOT NULL-Spalten, Defaultwerten, Identity-Spalte und Primärschlüssel ohne Check-Einschränkungen: CREATE TABLE Products ( ProductID int NOT NULL IDENTITY(1,1) PRIMARY KEY, ProductName nvarchar(50) NOT NULL, UnitPrice decimal(10,4) NOT NULL DEFAULT(0), UnitsInStock int NOT NULL DEFAULT(0), MinUnitsInStock int NOT NULL DEFAULT(0) ) Über NOT NULL geben Sie an, dass die Spalte keine NULL-Werte erlaubt. Die Option NULL würde NULL-Werte für die Spalte erlauben. IDENTITY(1,1) erzeugt eine Identity-Spalte mit Startwert 1 und Inkrement 1. Die Option PRIMARY KEY bewirkt, dass für diese Spalte ein Primärschlüssel erzeugt wird. Die Option DEFAULT(0) erzeugt den Defaultwert 0 für die Spalte. Erzeugen und Verwalten von Tabellen 53 :/ 4 , 2 Soll der Primärschlüssel über mehrere Felder gehen, müssen Sie die CONSTRAINT-Option (an Stelle der oben verwendeten PRIMARY KEY-Option) zur Erstellung des Primärschlüssels verwenden. Diese Variante besitzt zusätzlich den Vorteil, dass Sie den Namen des Primärschlüssels angeben können. Das folgende Beispiel erzeugt eine Tabelle Order_Details mit Primärschlüssel auf den Feldern OrderID und ProductID: CREATE TABLE Order_Details ( OrderID int NOT NULL, ProductID int NOT NULL, Quantity int NOT NULL DEFAULT(0), CONSTRAINT PK_Order_Details PRIMARY KEY CLUSTERED (OrderID, ProductID) ) :/" 4 , , ## ) > Per Default wird der Primärschlüssel mit einem gruppierten (clustered) Index erstellt. Wollen Sie dies vermeiden (weil Sie einen anderen Index gruppieren wollen), verwenden Sie die NONCLUSTERED-Option: CREATE TABLE Order_Details ( OrderID int NOT NULL, ProductID int NOT NULL, Quantity int NOT NULL DEFAULT(0), CONSTRAINT PK_Order_Details PRIMARY KEY NONCLUSTERED (OrderID, ProductID) ) :// & , , 4 Check-Einschränkungen legen Sie idealerweise über die CONSTRAINT-Option an (der SQL Server bietet auch alternative Möglichkeiten, die CONSTRAINT-Option ist jedoch die deutlichste). Das folgende Beispiel erzeugt eine Tabelle Artikel wie oben mit einer Check-Einschränkung auf dem Feld UnitPrice: CREATE TABLE Products ( ProductID int NOT NULL IDENTITY PRIMARY KEY, ProductName nvarchar(50) NOT NULL, UnitPrice decimal(10,4) NOT NULL DEFAULT(0), UnitsInStock int NOT NULL DEFAULT(0), MinUnitsInStock int NOT NULL DEFAULT(0), CONSTRAINT CK_Products_UnitPrice CHECK(UnitPrice >= 0) ) Wollen Sie eine Check-Einschränkung (oder jeder anderen Einschränkung) nachträglich anlegen, verwenden Sie dazu die ALTER TABLE-Anweisung: ALTER TABLE Products ADD CONSTRAINT CK_Products_UnitPrice CHECK(UnitPrice >= 0) Erzeugen und Verwalten von Tabellen 54 :/8 ) Indizes legen Sie separat über die CREATE INDEX-Anweisung an: CREATE [UNIQUE] [CLUSTERED | NONCLUSTERED] INDEX index_name ON table (column [,...n]) [WITH [PAD_INDEX] [[,] FILLFACTOR = fillfactor] [[,] IGNORE_DUP_KEY] [[,] DROP_EXISTING] [[,] STATISTICS_NORECOMPUTE] ] [ON filegroup] Beispiel: Nicht eindeutiger, nicht gruppierter Index mit Füllfaktor 75% auf der Spalte ProductName: CREATE NONCLUSTERED INDEX IX_Products_ProductName ON Products (ProductName) WITH FILLFACTOR=75 Wollen Sie einen vorhandenen Index ändern, müssen Sie den alten zuvor löschen: DROP INDEX Products.IX_Products_ProductName oder bei der Erstellung die Option DROP_EXISTING angeben: CREATE NONCLUSTERED INDEX IX_Products_ProductName ON Products (ProductName) WITH FILLFACTOR=75, DROP_EXISTING :/9 2 , Fremdschlüssel-Einschränkungen CONSTRAINT-Option. , 4 erstellen Sie wie Check-Einschränkungen über die Das folgende Beispiel erzeugt eine Beziehung zwischen der Products- und der Order_DetailsTabelle: ALTER TABLE Order_Details ADD CONSTRAINT FK_Order_Details_Products FOREIGN KEY (ProductID) REFERENCES Products (ProductID) :/: ? , 4 Wollen Sie vorhandene Einschränkungen ändern, müssen Sie die alten Constraints zuvor löschen. Dazu müssen Sie eine separate ALTER TABLE-Anweisung verwenden: ALTER TABLE Order_Details DROP CONSTRAINT FK_Order_Details_Products ALTER TABLE Order_Details ADD CONSTRAINT FK_Order_Details_Products FOREIGN KEY (ProductID) REFERENCES Products (ProductID) Erzeugen und Verwalten von Tabellen 55 :/@ ? ) Um einen Index zu löschen, muss der alte zuvor gelöscht werden: DROP INDEX Products.IX_Products_ProductName CREATE NONCLUSTERED INDEX IX_Products_ProductName ON Products (ProductName) :/A ) ) $# 7 , 4 Informationen zu den Spalten einer Tabelle erhalten Sie über die Stored Procedure sp_columns: sp_columns products Informationen zu Einschränkungen werden über die Stored Procedure sp_helpconstraint ausgegeben: sp_helpconstraint products Informationen zu Indizes gibt die Stored Procedure sp_helpindex aus: sp_helpindex products :8 ? 5 Beim Ändern von Tabellen benimmt sich der SQL Server recht freundlich. Sie können fast alle Eigenschaften einer Tabelle ändern, Spalten hinzufügen und löschen. Ändern Sie den Datentyp einer Spalte, die von anderen Tabellen referenziert wird, ändert der Enterprise Manager die Spalten in den anderen Tabellen (nach einer Nachfrage) automatisch. Auch Primärschlüssel, Fremdschlüssel, Check- und Unique-Einschränkungen können Sie nachträglich ändern. Erzeugen und Verwalten von Tabellen 56 @ @ % $- $ ! % Wie Sie schon bemerkt haben, erfordert der SQL Server einen gültigen Login, bestehend aus Loginname und Passwort, oder den Login über die Windows-Kontoinformationen. Diese Logins werden im SQL Server gespeichert, können von Benutzern mit entsprechenden Rechten verwaltet werden und sind Datenbank-übergreifend. Der Login in den SQL Server kann auf zwei Arten erfolgen: Mit der SQL ServerAuthentifizierung oder mit der Windows-Authentifizierung. Bei der SQL ServerAuthentifizierung muss der Login in den SQL Server explizit bei jedem Verbindungsaufbau erfolgen. Eine Anwendung kann die Login-Infos beim Aufbau der Verbindung mit übergeben (z. B. mit ADO in den entsprechenden Login-Argumenten des Connection-Objekts). Um den Anwendern den Login zu erleichtern, können Sie den SQL Server so konfigurieren, dass dieser automatisch den Login-Namen und das Passwort verwendet, mit dem der Anwender sich in Windows eingeloggt hat (Windows-Authentifizierung). Dazu ist allerdings Windows NT, 2000 oder XP als Server und idealerweise auch als Client erforderlich. Außerdem muss zum Client eine vertraute Verbindung (trusted Connection) bestehen. Vorteile der WindowsAuthentifizierung sind, dass der Anwender sich nur einmal in Windows einloggen muss und dass die Logins in Windows verwaltet werden können. @" ! % $- $ + , Der SQL Server unterscheidet zunächst systemweite Rechte (wie. z. B. das Recht, Datenbanken anlegen zu können) und datenbankspezifische Rechte (wie z. B. das Recht, in einer Tabelle Datensätze anzufügen). Datenbankspezifische Rechte können für jedes Objekt in der Datenbank für einzelne DB-Benutzer-Objekte vergeben werden. DB-Benutzer-Objekte werden in jeder Datenbank separat gespeichert. Um einen datenbankübergreifenden Login in den SQL Server zu ermöglichen, verwaltet dieser zusätzlich zu den DB-Benutzer-Objekten Login-Objekte (die in der deutschen Version des SQL Servers verwirrenderweise unter „Benutzernamen“ geführt werden, die englische Version verwendet den Begriff „Logins“). Ein Login-Objekt wird vom SQL Server automatisch mit einem gleichnamigen DB-Benutzer-Objekt jeder Datenbank verbunden, auf die dieser Login Zugriff erhält (siehe weiter unten). Der Sinn der getrennten Verwaltung von Logins und DB-Benutzern ist, dass Sie den DB-Benutzern unterschiedliche Rechte auf verschiedenen Datenbanken vergeben und auch den Zugriff auf bestimmte Datenbanken verbieten können. Sie können einzelnen DB-Benutzern Rechte auf Datenbankobjekte vergeben, besser ist in der Praxis jedoch die Verwaltung von Rollen und das Zuweisen dieser Rollen zu einzelnen Logins. Rollen ermöglichen, Rechte gruppenweise zu vergeben. So haben Sie z. B. in einer Bestelldatenbank eine Rolle „Besteller“. Dieser Rolle weisen Sie Leserechte auf allen Tabellen und das Recht „Anfügen“ und „Ändern“ auf den Tabellen „Bestellungen“ und „Bestelldetails“ zu. Für jede Person in Ihrer Firma, die Bestellungen aufnehmen soll, legen Sie einen Login an, vergeben das grundsätzliche Zugriffsrecht auf die Bestelldatenbank und weisen den einzelnen Logins die Rolle „Besteller“ zu. Sie können einem Login auch mehrere Rollen zuweisen. Wenn Sie die Windows-Authentifizierung verwenden, können Sie in Windows eine Gruppe anlegen und dort die einzelnen Benutzer dieser Gruppe verwalten. Im SQL Server müssen Sie dann nur einen einzelnen Login anlegen, der für diese Windows-Gruppe steht. Jeder Benutzer, der sich in Windows eingeloggt hat und einer Windows-Gruppe angehört, für die ein Login im SQL Server existiert, hat damit alle Rechte dieses Logins. Benutzerverwaltung 57 @/ 2 + + $ + 7 Der SQL Server definiert bereits einige feste Server-Rollen und feste Datenbank-Rollen, die Sie nicht verändern oder löschen können (mit Ausnahme der Public-Rolle) und zu denen Sie keine neuen Rollen hinzufügen können. Sie können jedoch diese Rollen einzelnen Logins zuweisen. Benutzerdefinierte Datenbank-Rollen definieren die Zugriffsrechte auf Datenbankobjekten und werden vom Datenbankbesitzer oder von einem Benutzer angelegt und definiert, der entsprechende Rechte besitzt. * $ + Rolle Bedeutung bulkadmin Mitglieder dieser Rolle können Massenoperationen wie das Importieren von externen Daten ausführen. dbcreator Mitglieder dieser Rolle können Datenbanken erzeugen und in der Struktur verändern. diskadmin Mitglieder dieser Rolle können Dateien verwalten. processadmin Mitglieder dieser Rolle können den SQL Server-Prozess verwalten. securityadmin Mitglieder dieser Rolle können die Logins verwalten. serveradmin Mitglieder dieser Rolle können Server-weite Einstellungen verwalten setupadmin Mitglieder dieser Rolle können Replikationen installieren und Extended Stored Procedures verwalten. sysadmin Mitglieder dieser Rolle können jede Operation auf dem Server ausführen. Dem Benutzer sa ist diese Rolle per Voreinstellung zugewiesen. Tabelle 7: Die vordefinierten festen Server-Rollen * + Rolle Bedeutung db_accessadmin Mitglieder dieser Rolle können Benutzer-Objekte von der Datenbank entfernen oder hinzufügen. db_backupoperator Mitglieder dieser Rolle können ein Backup der Datenbank erzeugen. db_datareader Mitglieder dieser Rolle können die Daten aller Tabellen der Datenbank lesen. db_datawriter Mitglieder dieser Rolle können die Tabellen der Datenbank beschreiben. db_ddladmin Mitglieder dieser Rolle können Objekte in der Datenbank verändern, löschen oder hinzufügen. db_denydatareader Diese Rolle verweigert alle Leserechte auf alle Objekte der Datenbank, auch wenn andere Rollen Leserechte vergeben. Damit können Sie Benutzern, die (zeitweise) »in Ungnade« verfallen sind, alle Leserechte entziehen, damit diese nicht mehr mit der Datenbank arbeiten können. Benutzerverwaltung 58 db_denydatawriter Diese Rolle verweigert alle Änderungsrechte auf alle Objekte der Datenbank, auch wenn andere Rollen Änderungsrechte vergeben. Wie bereits bei der Rolle db_denydatareader können Sie Benutzern, die (zeitweise) »in Ungnade« verfallen sind, alle Schreibrechte entziehen. db_owner Mitglieder dieser Rolle können alle Operationen auf der Datenbank ausführen. Diese Rolle definiert dieselben Rechte wie die, die der DBO besitzt. db_securityadmin Mitglieder dieser Rolle können Rollen und die Mitglieder dieser Rollen und Rechte auf Objekten der Datenbank verwalten. public Mitglieder dieser Rolle können nur die Operationen ausführen, für die explizit Rechte vergeben wurden. Tabelle 8: Die vordefinierten festen Datenbank-Rollen Der public-Rolle gehören automatisch alle DB-Benutzer-Objekte (und damit alle Logins) an. Sie können keinen Benutzer aus der Public-Rolle entfernen. Diese Rolle wird für Rechte verwendet, die alle Logins, die Zugriff auf eine bestimmte Datenbank besitzen, auf dieser Datenbank besitzen sollen. Die Public-Rolle ist die einzige feste Rolle, die Sie verändern können. Der Database Owner (dbo) ist derjenige Login, der eine Datenbank angelegt hat. Dieser Login besitzt alle Rechte auf der von ihm angelegten Datenbank. Der SQL Server verknüpft den Login, der eine Datenbank angelegt hat, automatisch mit dem dbo. In SQL-Anweisungen, in denen die Angabe des Besitzers eines Objekts notwendig ist, muss immer dbo verwendet werden, wenn der entsprechende Benutzer eingeloggt ist. @8 + Normalerweise werden Sie, nachdem die Datenbankstruktur festgelegt wurde, einzelne Rollen anlegen und diesen Rollen Rechte auf einzelne Objekte in dieser Datenbank vergeben. Sie können dabei Rollen auch verschachteln, das heißt, dass sie einer Rolle eine andere Rolle zuweisen. Nachdem die Rollen definiert sind, legen Sie wenn notwendig Logins an, geben diesen Logins Zugriff auf die Datenbank und weisen den Logins die definierten Rollen zu. Sie können auch jedem einzelnen Login Rechte zuweisen. Wenn Sie die Rechte aber in Rollen verwalten und den einzelnen Logins diese Rolle(n) zuweisen, wird die (in der Praxis recht komplexe) Administration der Rechte erheblich vereinfacht. Idealerweise sollte kein Login spezielle Rechte besitzen, sondern immer nur die, die über die ihm zugewiesenen Rollen definiert sind. Benötigt ein Benutzer ein spezielles Recht, erstellen Sie dazu einfach eine neue Rolle und weisen diese dem Benutzer zu. Sie vermeiden damit ein eventuell entstehendes »Durcheinander« bei dem Sie in der Praxis u. U. nicht erkennen können, welche Rechte ein Benutzer nun wirklich besitzt und warum bestimmte Rechte bei bestimmten Benutzern u. U. nicht verfügbar sind obwohl dies eigentlich der Fall sein sollte. Benutzerverwaltung 59 Wenn Sie die Windows-Authentifizierung verwenden, können Sie prinzipiell auch die Windows-Gruppen der Benutzer im SQL Server bekannt machen und diesen Rechte vergeben. Windows-Benutzer die einer dieser Gruppen angehören, erhalten damit (theoretisch) alle für die Gruppe definierten Rechten. Im Prinzip können Sie dann auf Rollen verzichten, da die Windows-Benutzergruppen eine ähnliche Funktion besitzen. Leider funktioniert diese Technik nach eigenen Erfahrungen nicht immer. In einigen (speziellen) Architekturen (Windows-NT-Server, Windows-2000-Clients) wurden in einem meiner Projekte die Gruppenrechte des Benutzers nicht korrekt ausgewertet, sodass Benutzer bestimmte Rechte nicht besaßen, die aber ihrer Windows-Gruppe zugewiesen waren. Als Lösung musste ich die einzelnen Windows-Benutzer im SQL Server bekannt machen und die Rechte über Rollen verwalten. @8 + # Das Anlegen von Rollen erfolgt im Enterprise-Manager über den ROLLEN-Eintrag. Über das Kontextmenü legen Sie neue Rollen an: Abbildung 29: Anlegen einer neuen Rolle Wenn sie bereits Logins definiert haben, können Sie dieser Rolle in diesem Schritt gleich die Logins zuweisen. Benutzerverwaltung 60 B + , Im nächsten Schritt weisen Sie dieser Rolle Rechte auf die Datenbank zu, was Sie erreichen können, indem sie auf die Rolle doppelklicken und in den Eigenschaften der Rolle den Berechtigungen-Schalter betätigen: Abbildung 30: Einstellung der Zugriffsrechte auf die Objekte einer Datenbank für eine Rolle Beachten Sie, dass jede Recht-Einstellung für jedes Objekt drei Zustände besitzt: Recht zugewiesen (Häkchen), Recht nicht zugewiesen (leeres Kästchen) und Recht verweigert (rotes Kreuz). Wenn ein Benutzer mehreren Rollen zugewiesen ist, wird immer das „sichere“ Recht verwendet. Wenn ein Recht in einer Rolle verweigert wird, besitzt der Benutzer dieses Recht nicht, auch wenn das Recht in einer anderen Rolle vergeben wurde. Ist ein Recht in einer Rolle lediglich nicht vergeben und in einer anderer Rolle vergeben, besitzt ein Benutzer, der beiden Rollen angehört, dieses Recht. Benutzerverwaltung 61 % , Anweisungsrechte sind solche, die das Erstellen von Datenbankobjekten und das Backup der Datenbank betreffen. Anweisungsrechte vergeben Sie über die Eigenschaften der Datenbank. Abbildung 31: Vergabe von Anweisungsrechten in den Datenbank-Eigenschaften Anweisungsrechte können Sie einzelnen Rollen und einzelnen Benutzern zuweisen. Benutzerverwaltung 62 @8" C % $- * % + , Das Zuweisen oder Verweigern von Rechten geht wesentlich einfacher mit SQL als mit dem Enterprise-Manager. Besonders dann, wenn Sie einer Rolle oder einem Benutzer alle oder fast alle Rechte vergeben wollen, sind sie mit SQL im Vorteil. Rechte vergeben Sie mit der GRANT-Anweisung. Für Anweisungsrechte gilt: GRANT {ALL | statement [,...n]} TO security_account [,...n] Mit ALL vergeben sie alle Rechte, ansonsten verwenden Sie die folgenden Angaben, um bestimmte Rechte zu vergeben: Anweisung Erlaubt das ... CREATE DATABASE Erzeugen von Datenbanken CREATE DEFAULT Erzeugen von Default-Wert-Objekten, die als Defaultwert für Spalten von Tabellen verwendet werden können. Ist lediglich aus Kompatibilitätsgründen zu älteren Versionen des SQL Servers enthalten. Verwenden Sie für spezielle Defaultwerte im SQL Server 2000 besser Funktionen. CREATE FUNCTION Erzeugen von Funktionen CREATE PROCEDURE Erzeugen von Stored Procedures CREATE RULE Erzeugen von Regeln CREATE TABLE Erzeugen von Tabellen CREATE VIEW Erzeugen von Sichten BACKUP DATABASE Sichern von Datenbanken BACKUP LOG Sichern des Transaktions-Protokolls Tabelle 9: Angaben für das Erteilen von Anweisungsrechten Objektrechte legen sie ähnlich an: GRANT {ALL [PRIVILEGES] | permission[,...n]} { [(column[,...n])] ON {table | view} | ON {table | view}[(column[,...n])] | ON {stored_procedure | extended_procedure} } TO security_account[,...n] [WITH GRANT OPTION] [AS {group | role}] Benutzerverwaltung 63 Mit ALL können Sie alle Rechte vergeben. Wenn Sie spezifische Rechte vergeben wollen, verwenden Sie die folgenden Angaben (nur Auszug, die komplette Liste finden Sie in der TSQL-Hilfe für die GRANT-Anweisung): Anweisung Erlaubt ... ALTER DATABASE das Verändern der Datenbankstruktur ALTER TABLE das Verändern der Struktur einer Tabelle ALTER PROCEDURE das Verändern einer Stored Procedure ALTER FUNCTION das Verändern einer Funktion ALTER VIEW das Verändern einer Sicht EXECUTE den Aufruf von Stored Procedures GRANT [ON Objekt] die Vergabe von Rechten für alle Objekte oder das angegebene Objekt INSERT das Anfügen von Datensätzen an die angegebene Tabelle SELECT das Anfügen von Datensätzen aus der angegebenen Tabelle UPDATE das Aktualisieren von Datensätzen in der angegebenen Tabelle Tabelle 10: Auszug aus den Angaben für das Erteilen von Objektrechten Das folgende Beispiel vergibt ein Leserecht auf die Tabelle Products für die Rolle Besteller: GRANT SELECT ON Products TO Besteller Sie können auch spaltenweise Rechte vergeben, indem sie die Spalten in Klammern vor dem Objekt angeben. Das folgende Beispiel vergibt das Aktualisierungsrecht auf die Spalten ProductName und UnitPrice der Tabelle Products an die Rolle Besteller: GRANT UPDATE (ProductName, UnitPrice) ON Products TO Besteller Entfernen können Sie Rechte über REVOKE. Wenn Sie ein Recht explizit verweigern wollen, verwenden Sie DENY. Beide Anweisungen arbeiten mit einer der GRANT-Anweisung ähnlichen Syntax. REVOKE entfernt nicht nur ein vergebenes Recht, sondern auch die Verweigerung eines Rechts. @8/ Wenn Sie Ihre Datenbank(en) und die zugehörigen Rollen angelegt haben, können sie im nächsten Schritt im Enterprise-Manager Logins anlegen, diesen Logins Zugriff auf die Datenbanken gewähren und den Logins die definierten Rollen zuweisen. Das Anlegen und Modifizieren von Logins geschieht über den BENUTZERNAMEN-Eintrag im SICHERHEIT-Ordner im Enterprise-Manager. Benutzerverwaltung 64 Abbildung 32: Definieren von Logins Hier können sie auch einstellen, ob für diesen Login die Windows-Authentifizierung verwendet wird oder die SQL Server-Authentifizierung. Daneben stellen sie ein, welche Datenbank die Default-Datenbank ist, wenn der Benutzer (oder eine Anwendung) keine spezielle Datenbank angibt. Im Register SERVERROLLEN können Sie angeben, welchen festen Server-Rollen der Login zugewiesen ist. Im Register DATENBANKZUGRIFF legen Sie fest, auf welche Datenbanken der Login grundsätzlichen Zugriff besitzt und welchen Rollen der Login zugewiesen ist. Benutzerverwaltung 65 Abbildung 33: Vergabe der Zugriffsrechte auf Datenbanken und Festlegen der Rollen Beachten Sie, dass sie in der oberen Liste zuerst die Datenbank auswählen müssen, um dem Login in der unteren Liste die Rollen zuweisen zu können. Für jeden Login legt der SQL Server automatisch einen Benutzer in der Datenbank an, der denselben Namen besitzt wie der Login. Diesen Benutzer können sie in der Datenbank separate Rechte vergeben, die der Login über seine Rollen nicht besitzt. Normalerweise reicht es jedoch aus, Rechte in Rollen zu definieren und einzelnen Logins diese Rollen zuzuweisen. @9 @9 $- $ Bei der SQL Server-Authentifizierung erfolgt der Login bei jedem Aufbau einer Verbindung explizit. Eine Anwendung muss beim Aufbau der Verbindung den Login-Namen und das Passwort an den SQL Server übergeben. Der Login muss mit dem Login-Namen und dem Passwort im SQL Server definiert sein, damit die Verbindung zustande kommen kann. Für diese Logins muss eingestellt sein, dass die SQL Server-Authentifizierung verwendet wird. @9" ! % Wenn auf allen Clients Windows NT, 2000, XP oder eine neuere Version verwendet wird, können Sie die Windows-Authentifizierung verwenden. Die Benutzer müssen sich dann nicht explizit in den SQL Server einloggen, da dieser die Informationen des Windows-Kontos des aktuellen Benutzers verwendet. Verwenden Sie die Windows-Authentifizierung nicht, muss ein Benutzer sich einmal in Windows und dann noch einmal in den SQL Server einloggen. Benutzerverwaltung 66 Im Idealfall verwalten sie alle SQL Server-Benutzer in Windows-Gruppen, denen sie jeweils einen SQL Server-Login zuweisen. Somit können Sie die Benutzer in Windows verwalten und die Rechte dieser Benutzer über den Login im SQL Server. Eine andere Möglichkeit ist, für jeden Windows-Benutzer einen separaten Login im SQL Server zu verwalten. Nach meinen Erfahrungen in einem Projekt kann es zu Problemen kommen wenn Sie nur die Benutzergruppen im SQL Server verwalten. Aus nicht nachvollziehbaren Gründen wurden bestimmte Rechte bestimmter Benutzer nicht korrekt erkannt, obwohl die Windows-Gruppe dieser Benutzer diese Rechte besaß. In diesem Projekt musst ich alle Benutzer einzeln im SQL Server bekannt machen und die Rechte über Rollen verwalten, damit alles reibungslos funktionierte. Das muss bei Ihnen nicht so sein, wenn Sie allerdings ähnliche Probleme haben, versuchen Sie einmal meine Lösung ... Nehmen wir an, Sie haben in der Windows-Domäne THE_GALAXY eine Gruppe Verleiher definiert, der bestimmte Anwender angehören. Für diese Gruppe erzeugen Sie im SQL Server einen Login, dem Sie die Windows-Gruppe zuweisen. Abbildung 34: Erzeugen eines Login für einen Windows-Benutzer Alle Benutzer, die einer Windows-Gruppe zugehören, besitzen damit automatisch alle Rechte des Logins, der die Windows-Gruppe im SQL Server abbildet. Sie können die der Gruppe zugehörigen Benutzer unter Windows verwalten, was auch noch den Vorteil hat, dass sie die Zugriffsrechte auf das System (also z. B. auf einzelne Dateien) gleichzeitig mit dem Zugriffsrechten für den SQL Server verwalten können. Wenn sie einzelne Windows-Benutzer einzelne Logins zuweisen wollen, geben Sie im Namen des Logins statt des Gruppennamens einfach dem Namen des Benutzers an. In der Regel kann der Client entscheiden, ob nun die SQL Server-Authentifizierung oder die Windows-Authentifizierung verwendet wird. Verwendet der Client zum Beispiel ADO zum Datenzugriff, wird beim Herstellen der Verbindung eingestellt, welche Art der Benutzerverwaltung 67 Authentifizierung verwendet wird. Der Query Analyzer (der ADO zum Zugriff auf den SQL Server verwendet) ist ein gutes Beispiel für diese Entscheidung. Abbildung 35: Login in den SQL Server durch den Query Analyzer @ : $# Der SQL Server unterstützt Benutzernamen und Logins mit spezieller Bedeutung: $6 ' ( Der Login sa stellt den Systemadministrator mit allen Rechten auf allen Objekten der Datenbank dar. Für den Systemadministrator-Login führt der SQL Server keinerlei Überprüfungen durch, d.h., der Systemadministrator arbeitet jenseits aller Schutzmechanismen und kann deshalb jede gewünschte Operation durchführen. Er ist gleichzeitig der einzige Eigentümer der Master-Datenbank und wird automatisch allen neu erstellten Datenbanken als Miteigentümer assoziiert. Der sa kann zeitweise die Identität anderer Benutzer annehmen: SetUser Name Damit kenn er z. B. für diesen Benutzer Objekte anzulegen. Mit SetUser ohne Parameter wird diese Zuweisung wieder aufgehoben. 0 Guest ist ein Benutzer, der vom Server verwendet wird, wenn ein Anwender mit einem gültigen Login, jedoch keinem gültigen Benutzer sich anmeldet. Dieser Login erhält dann die Rechte des Benutzers Guest falls dieser Benutzer definiert ist. ' ( Der dbo (Database Owner) ist der Benutzer, der eine Datenbank erstellt hat. Der dbo besitzt immer alle Rechte auf der betreffenden Datenbank und kann anderen Benutzern Rechte zuweisen oder entziehen. Eine Datenbank kann immer nur einem Benutzer gehören. Der Besitzer einer Datenbank kann nachträglich geändert werden. B Jeder Benutzer, der ein Datenbankobjekt erstellt hat wird zum Besitzer dieses Objekts und verfügt innerhalb seines Objekts über alle Berechtigungen. Benutzerverwaltung 68 A $, 7$ , 72 5 A Eine Sicht (engl. View, eine spezielle „Sicht“ auf die Daten) ist eine gespeicherte Auswahlabfrage. Über eine Sicht können Sie • komplexe Abfragen vor Clients verbergen. So können Sie zum Beispiel eine komplexe Abfrage in einer Sicht speichern. Ein Client führt nur einen SELECT, UPDATE, INSERT oder DELETE auf dieser Sicht aus und weiß nichts von der Komplexität der zugrunde liegenden Abfrage. • Benutzern Zugriffsrechte auf Tabellen oder Spalten geben, auf die diese normalerweise keine Rechte besitzen. • die Sicherheit komplexer verwalten, als dies mit Zugriffsrechten allein möglich ist (Beispiel dazu siehe unten). • die Performance erhöhen, da eine Sicht in der Datenbank bereits kompiliert ist und im SQL Server 2000 auch separat indiziert werden kann. Eine Stored Procedure ist eine in TSQL (Transact SQL, der dem SQL Server spezifische SQLDialekt) geschriebene SQL-Prozedur. TSQL erlaubt im Gegensatz zu ASCII-SQL einfache Programmstrukturen wie IF-Abfragen, WHILE-Schleifen und Variablen. TSQL besitzt besondere Bedeutung für Stored Procedures, Funktionen und Trigger. Stored Procedures können wie eine normale Funktionen Parameter besitzen, in denen sogar Werte zurückgegeben werden können, und als Funktion eine oder mehrere Datensatzlisten und einen Integerwert zurückgeben. Stored Procedures werden verwendet, um einen Teil der Geschäftslogik auf den Server zu verlagern. Oft bringt eine Stored Procedure, die eine bestimmte Aktion ausführt, einen Geschwindigkeitsvorteil gegenüber der Programmierung dieser Aktion in der Anwendung. Ein wesentlicher Vorteil von Stored Procedures ist jedoch, dass diese sehr einfach zentral auf dem Server gepflegt werden können. Eine Aktualisierung einer Stored Procedure ist sofort für alle Clients sichtbar, die diese verwenden. Die wesentliche Anwendung von TSQL erläutere ich im Folgenden bei der Beschreibung von Stored Procedures. Da Sie TSQL aber auch in Funktionen und Triggern einsetzen können, gilt alles das, was Sie zu TSQL bei den Stored Procedures lesen, auch für Funktionen und Trigger. Funktionen (neu im SQL Server 2000) sind das was sie auch in der Programmierung sind: Funktionen, denen Argumente übergeben werden können und die einen Wert zurückliefern. Das Besondere an SQL-Server-Funktionen ist, dass diese in SQL verwendet werden können, also in Abfragen, Sichten, Stored Procedures, Triggern und natürlich auch in anderen Funktionen. Mit Hilfe von Funktionen können Sie, wie bei Stored Procedures, einen Teil der Anwendungslogik bereits in der Datenbank speichern. So können Sie z. B. eine Funktion schreiben, die den gültigen Mehrwertsteuer-Prozentwert abhängig von einem übergebenen Datum zurückgibt. Wenn Sie diese Funktion überall dort einsetzen, wo die Mehrwertsteuer benötigt wird (in Sichten, Abfragen, Stored Procedures etc.), können Sie eventuelle Änderungen des Mehrwertsteuersatzes für zukünftige Datumswerte sehr einfach in der Datenbank berücksichtigen indem Sie einfach die Funktion umschreiben. Trigger sind Stored Procedures ähnlich. Der Unterschied ist, das Stored Procedures von außen aufgerufen werden, wogegen Trigger implizit aufgerufen werden, wenn auf eine Tabelle eine UPDATE, INSERT oder DELETE-Operation ausgeführt wird. Ein Trigger gilt immer für eine Tabelle und kann entweder nur auf UPDATE, INSERT oder DELETE reagieren oder auf eine Kombination dieser Aktionen. Ein Trigger besitzt zudem, im Gegensatz zu Stored Procedures, Sichten, Stored Procedures, Funktionen und Trigger 69 keine Parameter und kann keine Werte oder Datensatzlisten zurückgeben. Mit Hilfe eines Triggers kann z. B. eine komplexe Integritätsregel für einzelne Felder implementiert werden. Sinnvoll ist z. B. ein Trigger, der beim Anfügen neuer Datensätze in einer Kunden-Tabelle die nächste freie Kundennummer ermittelt und automatisch in das Feld Kunden_Nr einfügt oder ein Trigger, der beim Aktualisieren eines Kunden das Datum der letzten Änderung in einem entsprechenden Datumsfeld aktualisiert. A " $, A" $, Sichten können Sie recht einfach erzeugen, indem Sie im Kontextmenü des SICHTEN-Ordners im Enterprise Manager NEUE SICHT wählen. Der Enterprise Manager bietet Ihnen ein grafisches Tool zur Erstellung der Abfrage, das Sie recht einfach auch für komplexe Abfragen verwenden können. Abbildung 36: Der graphische Abfrage-Editor zum Erstellen von Sichten Das Schöne an diesen Editor ist, dass die Abfrage syntaktisch immer korrekt ist. In SQL erzeugen sie eine Sicht über: CREATE VIEW Sichtname [(Spaltenliste)] [WITH ENCRYPTION] AS Select_Anweisung [WITH CHECK OPTION] In der Abfrage geben Sie eine SELECT-Anweisung an. Basiert die Abfrage auf mehr als einer Tabelle, können Sie die Spaltennamen für Spalten, deren Name mehrfach vorkommen, in der optionalen Spaltenliste anpassen (einfacher wäre allerdings, die Spalten mit der AS-Klausel in der Abfrage umzubenennen). Die CHECK OPTION wird weiter unten erläutert. Sichten, Stored Procedures, Funktionen und Trigger 70 Das folgende Beispiel erzeugt eine Sicht auf die Produkte der Datenbank Northwind und deren Kategoriename: CREATE VIEW Products_With_Category_Name AS SELECT Products.ProductID, Products.ProductName, Categories.CategoryName FROM Products INNER JOIN Categories ON Products.CategoryID = Categories.CategoryID Wie bereits oben beschrieben, können Sie über eine Sicht Anwendern Zugriff auf Daten geben, auf die diese normalerweise keinen Zugriff hätten, und komplexe Abfragen gegenüber Anwendern bzw. Clients verbergen. Sichten bieten außerdem den Vorteil, dass die Abfrage bereits kompiliert ist und deswegen etwas schneller ausgeführt wird, als normale an den Server gesendete Abfragen. A"" * % $, Sichten werden verwendet wie Tabellen. Sie können Auswahlabfragen, aber auch Aktualisierungs-, Anfüge- und Löschabfragen auf der Sicht ausführen. Voraussetzung dafür ist allerdings, dass die der Sicht zugrunde liegende Abfrage das Aktualisieren, Anfügen bzw. Löschen zulässt. Das folgende Beispiel erzeugt eine Sicht, die alle Produkte der Kategorie 1 auflistet: CREATE VIEW Products_Of_Cat1 AS SELECT * FROM Products WHERE CategoryID = 1 Eine Auswahlabfrage würde dann z. B. folgendermaßen aussehen: SELECT * FROM Products_Of_Cat1 WHERE SupplierID = 16 Eine Aktualisierungsabfrage würde z. B. so aussehen: Update Products_Of_Cat1 SET UnitPrice = UnitPrice * 1.2 WHERE SupplierID = 16 Bei der Abfrage müssen Sie bedenken, dass die Sicht die Datensätze eventuell bereits einschränkt. Die Beispiel-Sicht zeigt z. B. grundsätzlich nur die Produkte der Kategorie 1. Eine Abfrage auf die Sicht berücksichtigt dann natürlich nur diese Produkte. A"/ $ $, Der SQL Server erlaubt keine direkten Sortierungen in Sichten. Das ist sinnvoll, denn eigentlich soll derjenige, der die Sicht später aufruft, eine spezielle Sortierung angeben können. In einigen Fällen ist es aber sinnvoll, eine Sicht schon per Voreinstellung zu sortieren. Über einen kleinen Trick ist dies möglich: Der SQL Server erlaubt das Sortieren in einer Sicht, wenn die TOPKlausel verwendet wird. Mit TOP 100 PERCENT können Sie nun alle Daten auslesen und trotzdem sortieren: CREATE VIEW Products_With_Category_Name AS SELECT TOP 100 PERCENT Products.ProductID, Products.ProductName, Categories.CategoryName FROM Products INNER JOIN Categories ON Products.CategoryID = Categories.CategoryID ORDER BY Products.ProductName U. U. wird die Sicht mit TOP 100 PERCENT etwas langsamer ausgeführt als wenn diese nachträglich sortiert wird, was besonders dann gilt, wenn die Sicht beim Aufruf sortiert wird. Sie sollten dies in der Praxis einfach testen. Hilfreich dabei ist der SQL Profiler, den Sie über das EXTRAS-Menü Des Enterprise-Managers aufrufen können. Sichten, Stored Procedures, Funktionen und Trigger 71 A"8 & , # Normalerweise erlaubt eine Sicht: • die enthaltenen Datensätze so zu ändern, dass diese nicht mehr den Kriterien (der WHEREKlausel) entsprechen und folglich aus der Sicht (beim nächsten Aufruf) entfernt werden; • neue Datensätze anzufügen, die den Kriterien der Sicht entsprechen und beim nächsten Aufruf der Sicht nicht erscheinen. Das folgende Beispiel ändert die Kategorie der Produkte, die vom Lieferant 16 geliefert werden, über die Sicht Products_of_Kat1: UPDATE Products_Of_Cat1 SET CategoryID = 2 WHERE SupplierID = 16 Genauso können Sie über diese Sicht z. B. auch ein Produkt hinzufügen, das der Kategorie 2 angehört: INSERT INTO Products_Of_Cat1 VALUES ('Test', 16, 2, NULL, 11.25, 0, 0, 10, 0) Dieses nicht intuitive Verhalten der Sicht können Sie mit der Check-Option unterbinden: CREATE VIEW Products_Of_Cat1 AS SELECT * FROM Products WHERE CategoryID = 1 WITH CHECK OPTION Eine Abfrage, die die enthaltenen Datensätze so ändert, dass diese aus der Sicht entfernt würden oder neue Datensätze anfügt, die nicht in der Sicht erscheinen würden, schlägt nun mit einer Fehlermeldung fehl. A"9 % $, $, Da Sie in Sichten auch Systemfunktionen einsetzen können, können Sie mit diesen auch eine erweiterte Sicherheit in ihrer Datenbank realisieren. Eine sinnvolle Anwendung wäre zum Beispiel die folgende: Ein Trigger sorgt in Ihrer Datenbank dafür, dass der Benutzer, der einen Datensatz in der Bestelltabelle anlegt, mit seinem Login Namen in einem speziellen Feld der Tabelle festgehalten wird. Keinem der Sachbearbeiter, die Bestellungen bearbeiten können, wird das Anfüge-, das Auswahl-, das Lösch- und das Aktualisierungsrecht auf die Bestelltabelle direkt vergeben. Diese Rechte werden einer Sicht vergeben, die folgendermaßen definiert ist: CREATE VIEW User_Orders AS SELECT OrderId, OrderDate, CustomerId FROM Orders WHERE User_Created = SESSION_USER WITH CHECK OPTION In dieser Sicht wird die Systemfunktion SESSION_USER verwendet, die den Namen des Logins zurückgibt, der die Sicht aufgerufen hat. Da eine Sicht grundsätzlich wie eine Tabelle verwendet werden kann, kann nun jeder Sachbearbeiter ausschließlich seine eigenen Bestellungen sehen und bearbeiten. Voraussetzung dafür ist natürlich, dass alle Anwendung diese Sicht an Stelle der Tabelle verwenden. Idealerweise besitzen die Sachbearbeiter in diesem Beispiel auf der Tabelle selbst keine Rechte, sondern nur auf der Sicht. Sichten, Stored Procedures, Funktionen und Trigger 72 A": $, 4 Sichten können Sie sehr einfach über die ALTER-Anweisung verändern: CREATE VIEW Products_Of_Cat1 AS SELECT * FROM Products WHERE CategoryID = 1 WITH CHECK OPTION Vorteil dabei ist, dass der SQL Server Rechte, die auf die Sicht gesetzt sind, beibehält, was nicht der Fall wäre, wenn Sie die Sicht löschen und wieder neu erzeugen würden. A/ $ A/ , $ , Eine Stored Procedure definieren Sie recht einfach, indem Sie im Enterprise Manager im Kontextmenü des Ordners GESPEICHERTE PROZEDUREN in einem Datenbank-Ordner den Befehl NEUE GESPEICHERTE PROZEDUR wählen. Im Dialog zur Erstellung von Stored Procedures wird Ihnen eine neue Stored Procedure angezeigt. Abbildung 37: Das Fenster zum Erstellen und Verändern von Stored Procedures Stored Procedures gelten immer für eine Datenbank und können tabellenübergreifend arbeiten. Geben Sie zunächst für <PROCEDURE NAME> einen Namen für Ihre Stored Procedure ein. Sichten, Stored Procedures, Funktionen und Trigger 73 Abbildung 38: Einfache Stored Procedure vor dem Speichern Achten Sie besonders auf die korrekte Schreibweise von verwendeten Bezeichnen, also Spaltennamen und Tabellennamen. Sie können über den Schalter SYNTAX ÜBERPRÜFEN zwar die grundsätzliche Syntax der Stored Procedure testen, aber nicht, ob verwendete Tabellen oder Spalten auch existieren. Speichern Sie diese Stored Procedure über den OK-Schalter. Kann die Stored Procedure gespeichert werden (d. h, dass sie keine Fehler enthält), fügt der Manager automatisch Code hinzu, der beim Speichern dafür sorgt, dass zuvor eine bereits definierte gleichnamige Stored Procedure gelöscht wird. Testen können Sie Stored Procedures über den Query Analyzer über die EXECUTE-Anweisung (die allerdings optional ist). Für unser Beispiel wäre ein Aufruf z. B.: EXECUTE Get_Kunden Eine Stored Procedure kann mit derselben Syntax auch mit SQL direkt erzeugt werden: CREATE PROC[EDURE] procedure_name [;number] [ {@parameter data_type} [VARYING] [= default] [OUTPUT] ] [,...n] [WITH { RECOMPILE | ENCRYPTION | RECOMPILE, ENCRYPTION } ] [FOR REPLICATION] AS sql_statement [...n] Sichten, Stored Procedures, Funktionen und Trigger 74 A/" + , 6# $ , Eine Stored Procedure kann eine oder mehrere Datensatzlisten und/oder einen Integer-Datentyp zurückgeben. Nur das Ergebnis einer Stored Procedure, die eine Datensatzliste zurückgibt, können Sie im SQL Query Analyzer direkt sehen. Für alle anderen kommt nur die Meldung, dass diese keine Datensatzlisten zurückgeben. Eine Datensatzliste wird immer dann zurückgegeben, wenn Sie mit innerhalb der Stored Procedure eine normale Auswahlabfrage (also eine Abfrage, die einzelne Felder zurückgibt) schreiben. Da Sie mit einer SELECT-Anweisung auch Variablen Werte zuweisen können, muss ein solches nicht immer auch eine Datensatzliste zurückgeben. Das Beispiel oben gibt alle Felder der Products-Tabelle zurück: SELECT * FROM Products Die Rückgabe als Datensatzliste muss jedoch nicht unbedingt einer Tabelle entnommen werden. So können Sie mit SELECT auch selbstdefinierte Datensatzlisten zurückgeben. Die folgende Abfrage: SELECT "Hello World" AS Begrüßung, "Jürgen" AS Name ergibt z. B. Begrüßung Name ----------- -----Hello World Jürgen (1 row(s) affected) Wenn eine Stored Procedure einen Integer-Datentyp zurückgeben soll, geben Sie diesen mit RETURN Wert zurück. Für den Wert können Sie natürlich auch eine Variable oder einen Ausdruck einsetzen. Beachten Sie, dass eine Stored Procedure nur Integer-Datentypen zurückgeben kann, keine anderen Werte wie z. B. Dezimalwerte oder Zeichenketten. Wenn Sie z. B. eine real-Variable mit RETURN @Variable zurückgeben, konvertiert der SQL Server den Wert in den entsprechenden Integerwert um. Wenn Sie Dezimal-Datentypen oder Zeichenketten zurückgeben wollen, müssen Sie dazu OUTPUT-Argumente verwenden (siehe weiter unten). Eine solche Rückgabe kann beim Aufruf einer Stored Procedure aus einer Anwendung heraus verwendet werden. Wie dies für ein VBA-Programm implementiert wird, erfahren Sie weiter unten. Sinnvoll ist die Verwendung eines Rückgabewertes immer dann, wenn eine Stored Procedure eine Aktion ausführen soll, die gar keine Datensatzliste ergibt, z. B. den Update eines Artikel-Preises in der Artikeltabelle, oder wenn der Erfolg einer Aktion ausgewertet werden soll. Eine weitere Möglichkeit, Werte zurückzugeben, ist die Verwendung von OUTPUT-Parametern, die ich im nächsten Abschnitt beschreibe. A// * Eine Stored Procedure kann in der Parameterliste, die in Klammern dem Prozedurnamen folgt, Input- und Output-Parameter besitzen. Ein Parameter wird durch @Name Datentyp [VARYING] [= default] [OUTPUT] deklariert. Der Name folgt den üblichen Regeln für Bezeichner (beginnt mit einem Buchstaben, kann Zahlen, Buchstaben und den Unterstrich enthalten). Der Datentyp entspricht den unten beschriebenen Datentypen für Variablen. Sichten, Stored Procedures, Funktionen und Trigger 75 Beispiel: Stored Procedure, der eine Kunden-Nummer übergeben wird, und die den Kunden mit dieser Kunden-Nummer zurückgibt: CREATE PROCEDURE Get_Kunde(@Kunden_Nr int) AS SELECT * FROM Kunden WHERE Kunden_Nr = @Kunden_Nr Wenn Sie über einen Parameter Werte zurückgeben wollen, geben Sie OUTPUT mit an. OutputParameter werden weiter unten beschrieben. Mit der Option VARYING können Sie in Parametern Datensatzlisten zurückgeben. Der Parameter muss dazu ein Cursor-Datentyp sein. Da Sie dies wahrscheinlich nur in sehr komplexen Programm benötigen, wird diese Option hier nicht beschrieben. Wenn Sie einen Defaultwert angeben, muss beim Aufruf der Prozedur anstelle dieses Parameter kein Wert übergeben werden. Wird kein Wert übergeben, verwendet die Prozedur den Defaultwert. Da Sie in TSQL auch programmieren können, benötigen sie in vielen Stored Procedures auch Variablen. Variablen werden folgendermaßen deklariert: DECLARE @Name Datentyp [,@Name Datentyp] [...] Das @-Zeichen vor dem eigentlichen Namen ist für Parameter und Variablen obligatorisch. Für Parameter und Variablen können Sie fast alle der in Kapitel 6.1.1 beschriebenen Datentypen verwenden. Häufig werden die Typen int, double und nvarchar(n) eingesetzt. Sie können einem Parameter oder einer Variablen mit SET @Variable = Wert einen Wert zuweisen. Das folgende Beispiel speichert einen Parameterwert in einer Variablen: CREATE PROCEDURE Get_Kunde(@Kunden_Nr int) AS DECLARE @ID int SET @ID = @Kunden_Nr SELECT * FROM Kunden WHERE Kunden_Nr = @ID Einer Variablen können Sie außerdem einen Wert über eine Auswahlabfrage zuweisen: SELECT @Variable=Ausdruck FROM ... Der Ausdruck ist in der Regel ein einfaches Datenfeld, eine arithmetische Berechnung, oder eine Aggregatfunktion. Außerdem können Sie Parameter oder Variablen in einer Abfrage einsetzen. Das folgende Beispiel holt die größte ProductID aus der Tabelle Products und gibt diese um 1 addiert zurück: CREATE PROCEDURE Get_Next_ProductId AS /* Deklaration einer Variablen */ DECLARE @ProductID int /* Zuweisen der größten ProductID zu der Variablen @ProductID */ SELECT @ProductID = MAX(ProductID) FROM Products /* Rückgabe einer selbst erzeugten Datensatzliste (mit einem Datensatz) mit dem Ergebnis */ SELECT @ProductID + 1 AS Next_Product_Id Dieses Beispiel gibt die ermittelte ProductID in einer Datensatzliste mit einem einzigen Datensatz und einem Feld Next_Product_Id zurück. Beachten Sie, dass die erste SELECTAnweisung keine Datensatzliste ergibt, weil ausschließlich Zuweisungen an Variablen erfolgen. Das Ergebnis der Stored Procedure ist also nur eine Datensatzliste. Sinnvollerweise könnte die Stored Procedure den ermittelten Wert direkt als Funktionsrückgabewert zurückgeben (beachten Sie dabei, dass Stored Procedures nur IntegerWerte im Funktionsrückgabewert zurückgeben können): Sichten, Stored Procedures, Funktionen und Trigger 76 CREATE PROCEDURE Get_Next_ProductId AS /* Deklaration einer Variablen */ DECLARE @ProductID int /* Zuweisen der größten ProductID zu der Variablen @ProductID */ SELECT @ProductID=MAX(ProductID) FROM Products /* Rückgabe einer selbst erzeugten Datensatzliste (mit einem Datensatz) mit dem Ergebnis */ RETURN @ProductID + 1 Wollen Sie Prozeduren, die einen Integer-Wert zurückgeben, testen, müssen sie diese im Query Analyzer etwas anderes aufrufen: DECLARE @ProductID int EXECUTE @ProductID = Get_Next_ProductId SELECT @ProductID AS Next_ProductID * % # Output-Parameter sind äquivalent zu By Reference-Argumenten in Programmiersprachen wie C, C++, C#, oder Visual Basic(.NET). In Output-Parametern können Sie Werte beliebigen Datentyps zurückgeben, was besonders bei Stored Procedures interessant ist, da diese im Funktionsrückgabewert nur Integer-Werte zurückgeben können. Die Verwendung von Output-Parametern ist eigentlich recht einfach. Deklarieren Sie einen Parameter einfach mit OUTPUT. Werte, die Sie (mit SET oder SELECT) in diesen Parameter schreiben, können nach dem Aufruf der Stored Procedure in einer Anwendung sehr einfach ausgelesen werden. Wie das prinzipiell funktioniert, erfahren Sie im nächsten Abschnitt. A/8 $ , # * Stored Procedures werden häufig in programmierten Anwendungen eingesetzt, um möglichst viel von der Geschäftslogik in den Server zu verlagern. Man spricht hier übrigens von einem 2Schichten-Modell (oder 2-Tier-Model). Die Benutzerschicht stellt die für die Bearbeitung der Daten erforderlichen Oberflächen dar, die Datenschicht speichert die Daten. Bei 2-SchichtenModellen liegt häufig die gesamte Logik auf dem Client. Mit Stored Procedures können Sie Teile der Logik auf den Server verlagern. Dieses Modell wird jedoch teilweise auch wieder in Frage gestellt, nämlich durch das 3-Schichten-Modell. Bei diesem Modell wird die Geschäftslogik (die z. B. definiert, in welcher Form auf die Kundentabelle zugegriffen werden kann) in separaten Objekten definiert, die zentral auf einem Server im Netzwerk laufen und die ausschließlich den Datenzugriff erledigen. Über DCOM, CORBA, .NET-Remoting, Webdienste oder andere Techniken kann eine Anwendung ohne direkten Zugriff auf die Datenbank deren Daten trotzdem über diese mittlere Schicht, die Geschäftslogik-Schicht bearbeiten. Bei diesem Modell stellt sich dann allerdings die Frage, ob Stored Procedures eingesetzt werden oder nicht. Aus Performancegründen ist die Entscheidung für Stored Procedures allerdings auch im 3Schichten-Modell häufig die richtige. In einem VBA-Programm können Sie zum Aufruf einer Stored Procedure ein ADO-CommandObjekt verwenden. Den Namen der Prozedur übergeben Sie in der Eigenschaft CommandText. Wenn Sie CommandType auf adCmdStoredProc setzen, wird die Ausführung ein wenig beschleunigt. Sie benötigen eine Verbindung zu der Datenbank, die Sie vor der Ausführung über ein Connection-Objekt öffnen müssen und in die Eigenschaft ActiveConnection schreiben. Wenn die Prozedur Parameter besitzt, müssen Sie diese entweder über die CreateParameter-Methode des Command-Objekts erzeugen und dabei gleich der Parameters-Auflistung mit deren Append-Methode anhängen, oder Sie erzeugen ein separates Parameter-Objekt, setzen dessen Eigenschaften und hängen dies der Parameters- Sichten, Stored Procedures, Funktionen und Trigger 77 Auflistung an. In beiden Varianten müssen Sie verschiedene Einstellungen vornehmen, die am Beispiel der CreateParameter-Methode beschrieben werden: Set Parameter = command.CreateParameter( _ [Name] [, Type] [, Direction,] [, Size] [, Value]) Name ist der Objektname. Type spezifiziert den Typ des Parameters. Sie können die folgenden Konstanten einsetzen (nur die wichtigsten werden hier aufgelistet; in der ADO-Dokumentation, die mit den MDAC-Komponenten installiert wird, finden Sie unter der Type-Eigenschaft alle Konstanten): Konstante Bedeutung (Datenbank-Typkonstante in Klammern) adBigInt 8 Byte Integer mit Vorzeichen (DBTYPE_I8). adBinary Binärer Wert (DBTYPE_BYTES). adBoolean Boolescher Wert (DBTYPE_BOOL). adByRef wird über OR mit einer anderen Konstanten verknüpft, um festzulegen, dass der Parameter ein Zeiger auf den anderen Datentyp ist (DBTYPE_BYREF). adBSTR Nullterminierter Unicode-String (DBTYPE_BSTR). adChar String (DBTYPE_STR). adCurrency 8 Byte-Währungswert (DBTYPE_CY). adDate Date-Wert (DBTYPE_DATE). Wird verwaltet wie in Visual Basic (Ganzzahlanteil stellt die Anzahl der Tage seit dem 30.12.1899 dar, Nachkommaanteil die Sekunden) adDBDate Datumswert im Format yyyymmdd (DBTYPE_DBDATE). adDBTime Zeitwert im Format hhmmss (DBTYPE_DBTIME). adDouble Double-Wert (DBTYPE_R8). adEmpty definiert, dass kein Wert übergeben wird (DBTYPE_EMPTY). adInteger 4 Byte Integer mit Vorzeichen (DBTYPE_I4). adIUnknown Vorsicht: Hiermit ist nicht gemeint, dass der Datentyp unbekannt ist, sondern dass es sich um einen Zeiger auf ein COM-Interface vom Typ IUnknown handelt. (DBTYPE_IUNKNOWN). adSingle Single-Wert (DBTYPE_R4). adSmallInt 2 Byte Integer mit Vorzeichen (DBTYPE_I2). adTinyInt 1 Byte Integer mit Vorzeichen (DBTYPE_I1). adUnsignedBigInt 8 Byte Integer ohne Vorzeichen (DBTYPE_UI8). adUnsignedInt 4 Byte Integer ohne Vorzeichen (DBTYPE_UI4). adUnsignedSmallInt 2 Byte Integer ohne Vorzeichen (DBTYPE_UI2). adUnsignedTinyInt 1 Byte Integer ohne Vorzeichen (DBTYPE_UI1). adUserDefined Benutzerdefinierter Typ (Zeiger auf eine Struktur) (DBTYPE_UDT). adVarBinary Binärwert, der in der Datenbank mit variabler Größe gespeichert wird. adVarChar String, der in der Datenbank mit variabler Größe gespeichert wird.. Sichten, Stored Procedures, Funktionen und Trigger 78 adVariant Variant-Wert (DBTYPE_VARIANT). adVarWChar Nullterminierter Unicode-String, der in der Datenbank mit variabler Größe gespeichert wird. adWChar Nullterminierter Unicode-String (DBTYPE_WSTR). Tabelle 11: ADO-Datentypen um Vergleich zu den SQL-Server-Datentypen Direction sagt aus, ob der Parameter einen Wert in die Prozedur schreibt oder die Prozedur einen Wert im Parameter zurückgibt oder beides: Konstante Bedeutung adParamInput Default: Der Parameter wird in die Stored Procedure geschrieben. adParamOutput Der Parameter wird von der Gespeicherten Prozedur gesetzt. adParamInputOutput Der Parameter wird in die Prozedur geschrieben und von der Prozedur gesetzt. adParamReturnValue Diesen Wert geben Sie für den ersten Parameter der ParametersAuflistung an, wenn die Prozedur eine Funktion ist, die einen Wert zurückgibt. Tabelle 12: ADO-Konstanten für Parameter-Richtungen Sie müssen die korrekte, in der gespeicherten Prozedur definierte Einstellung für Direction angeben, da beim Aufruf der Stored Procedure ansonsten entweder die Daten inkorrekt oder gar nicht übergeben werden oder ein Laufzeitfehler erzeugt wird. Size bestimmt die maximale Größe eines Parameter mit Daten variabler Länge. Wenn Sie bei diesen Daten die Maximallänge nicht angeben, wird beim Anhängen des Parameter-Objekts an die Parameters-Auflistung oft ein Laufzeitfehler erzeugt. Der Grund liegt darin, dass ADO für Parameter mit variabler Länge soviel Speicherplatz reserviert, wie der Datentyp potentiell benötigt, was jedoch zu wenig sei kann. + , % Wenn eine Stored Procedure eine Funktion ist, also einen Wert zurückgibt, müssen Sie den Parameters(0) mit ersten Parameter der Parameters-Auflistung Direction=adParamReturnValue versehen. Dieser Parameter enthält nach der Ausführung der Prozedur den Rückgabewert. Lassen Sie sich nicht verwirren: Eine Gespeicherte Prozedur kann einen Rückgabewert besitzen und/oder ein Recordset-Objekt erzeugen. Das Recordset-Objekt wird von der Execute-Methode des Command-Objekts zurückgegeben. Wenn alle Parameter angehangen sind, führen Sie die Prozedur mit der Execute-Methode aus. Für Prozeduren, die Recordsets erzeugen, gilt: Set Recordset = command.Execute([RecordsAffected] [,Parameters] [,Options]) Für Prozeduren, die keine Recordsets erzeugen, gilt: command.Execute [RecordsAffected] [,Parameters] [,Options] In RecordsAffected können Sie eine Long-Variable einsetzen, in der nach der Ausführung die Anzahl der betroffenen Datensätze gespeichert ist. In Parameters können Sie alternativ zum Anhängen der Parameter an deren Kollektion Parameter in einem Variant-Array übergeben. Diese Variante hat jedoch den Nachteil, dass Rückgabewerte ignoriert werden. Options definiert Sichten, Stored Procedures, Funktionen und Trigger 79 den Typ des Befehls und sollte hier auf adCmdStoredProc gesetzt werden. Alternativ können Sie die Eigenschaft CommandType verwenden. # Aufruf der Prozedur byroyalty in der Pubs-Datenbank des Microsoft SQL Server, die ermittelt, welche Autoren mit dem übergebenen Prozentwert an den Tantiemen ihrer Bücher beteiligt sind: Dim cmd As ADODB.Command, conn As ADODB.Connection Dim rst As ADODB.Recordset Set cmd = New ADODB.Command Set conn = New ADODB.Connection conn.Open "PROVIDER=MSDASQL;DSN=Pubs;UID=sa;PWD=honda" cmd.CommandText = "byroyalty" ' Name der Gespeicherten Prozedur cmd.CommandType = adCmdStoredProc ' Typ des Befehls Set cmd.ActiveConnection = conn ' Verbindung für die Ausführung ' Parameter erzeugen und direkt anhängen cmd.Parameters.Append cmd.CreateParameter("", adInteger, _ adParamInput, 2, 50) Set rst = cmd.Execute While Not rst.EOF List1.AddItem rst.Fields(0).Value rst.MoveNext Wend rst.Close A/9 0 * Innerhalb von Stored Procedures können Sie globale Variablen verwenden. Globale Variablen erkennen Sie an einem doppelten @. Im Folgenden finden Sie eine Auswahl der wichtigsten Variablen: Variable Bedeutung @@CONNECTIONS Die Anzahl der aktuellen und der versuchten Logins seit dem Start des SQL Servers @@ERROR Der letzte vom System erzeugte Fehler. Verwenden Sie @@ERROR, um den Fehlerstatus der zuletzt ausgeführten Anweisung zu ermitteln. Sie können den Fehler mit RAISERROR auch an den Benutzer weitergeben. @@FETCH_STATUS Der Status des letzten Fetch bei der Verwendung von Cursorn (siehe unten) @@ROWCOUNT Die Anzahl der von der letzten Anweisung betroffenen Zeilen. Wird von nahezu jeder Anweisung gesetzt, weswegen Sie das unten beschriebene beachten sollten. @@SERVERNAME Der Name des SQL Servers @@TRANCOUNT Die Anzahl der momentan aktiven Transaktionen für den aktuellen Benutzer @@VERSION Die Versionsnummer des SQL Servers Tabelle 13: Wichtige globale Variablen des SQL Servers Beachten Sie bei @@ROWCOUNT, dass eigentlich jede Anweisung (nicht nur SQLAnweisungen) @@ROWCOUNT setzt. Idiotischerweise macht dies sogar die IFAnweisung. Statt Sichten, Stored Procedures, Funktionen und Trigger 80 UPDATE Artikel SET Preis = Preis * .01 IF @@ROWCOUNT > 0 BEGIN /* Anweisungen */ END müssen Sie den folgenden Programmcode verwenden: DELARE @RowCount int UPDATE Artikel SET Preis = Preis * .01 SELECT @RowCount = @@ROWCOUNT IF @RowCount > 0 BEGIN /* Anweisungen */ END A/: 5$- 1 TSQL bietet einige einfache Kontrollstrukturen zur Programmierung, wie die IF- und die WHILE-Anweisung. Bei der Verwendung dieser Strukturen müssen Sie beachten, dass sich die Anweisungen immer nur auf die nächste Zeile beziehen, wenn sie keine Blöcke verwenden. Ein Block wird eingeleitet durch das Schlüsselworte BEGIN und beendet durch das Schlüsselworte END. Die Syntax der IF-Abfrage sieht folgendermaßen aus: IF Boolean_expression {sql_statement | statement_block} [ELSE {sql_statement | statement_block}] Die Syntax der WHILE- Schleife: WHILE Boolean_expression {sql_statement | statement_block} [BREAK] {sql_statement | statement_block} [CONTINUE] Mit BREAK können Sie eine WHILE-Schleife abbrechen, mit CONTINUE können Sie außerhalb der WHILE-Schleife diese wieder neu starten. Einfaches Beispiel für WHILE und IF: DECLARE @Counter int SET @Counter = 0 WHILE @Counter < 10 BEGIN IF @Counter = 5 BEGIN PRINT "Zähler ist 5" END ELSE BEGIN PRINT "Zähler ist nicht 5" END SET @Counter = @Counter + 1 END In diesem Beispiel wird die PRINT-Anweisung verwendet, um Testausgaben im Query Analyzer zu erzeugen. Sinnvolles Beispiel: Erhöhen des Artikelpreises um je 10%, solange, bis entweder der durchschnittliche Preis größer/gleich 30 ist oder der höchste Preis größer als 300: WHILE (SELECT AVG(UnitPrice) FROM Products) < 30 BEGIN Sichten, Stored Procedures, Funktionen und Trigger 81 UPDATE Products SET UnitPrice = UnitPrice * 1.1 IF (SELECT MAX(UnitPrice) FROM Products) > 300 BREAK END Wie Sie in diesem Beispiel sehen, können Sie eine Abfrage, die einen Wert zurückgibt, auch in Ausdrücken verwenden. Zur Strukturierung ihres Programms können sie zudem die CASE-Anweisung verwenden, die in zwei Varianten vorliegt: Variante 1: CASE input_expression WHEN when_expression THEN result_expression [...n] [ELSE else_result_expression] END Diese Variante von CASE entspricht im Wesentlichen dem Case von VBA. Der in input_expression übergebene Wert wird mit den in when_expression übergebenen Werten verglichen. Wenn ein Vergleich wahr wird, wird der in result_expression übergebene Wert allerdings von CASE wie ein Funktionsrückgabewert zurückgegeben. Beispiel: DECLARE @Counter int SET @Counter = 0 WHILE @Counter < 10 BEGIN PRINT CASE @Counter WHEN 1 THEN "Zähler ist 1" WHEN 2 THEN "Zähler ist 2" ELSE "Zähler ist weder 1 noch 2" END SET @Counter = @Counter + 1 END Variante 2: CASE WHEN Boolean_expression THEN result_expression [...n] [ELSE else_result_expression] END Diese Version von CASE arbeitet ähnlich der ersten Variante, nur dass im WHEN-Block ein Vergleichsausdruck verwendet wird. Sichten, Stored Procedures, Funktionen und Trigger 82 A/@ 5$- # TSQL kennt natürlich auch die gängigen Operatoren, die ich hier nur kurz beschreibe. Für nähere Informationen lesen Sie gegebenenfalls in der TSQL-Hilfe nach. C % , # Operator Bedeutung = Zuweisung + Addition von Zahlen oder Zeichenketten - Subtraktion * Multiplikation / Division % Restwert-Division Tabelle 14: Die TSQL-Zuweisungs- und die arithmetischen Operatoren * , # Operator Bedeutung = Gleichheit > Größer >= Größer / Gleich < Kleiner <= Kleiner / Gleich <> oder != Ungleich !< Nicht kleiner als !> Nicht größer als Tabelle 15: Die TSQL-Vergleichs-Operatoren , # Operator Bedeutung ALL ergibt TRUE wenn der linke Operand in einer rechts angegebenen Menge vorkommt. Die Menge wird in Klammern entweder als kommabegrenzte Wertliste geschrieben oder über eine Unterabfrage ermittelt. AND ergibt TRUE wenn zwei boolesche Ausdrücke TRUE ergeben. ANY ergibt TRUE wenn mindestens ein Vergleiche in einer Menge TRUE ergibt. BETWEEN x AND y ergibt TRUE wenn der Wert des linken Operanden zwischen x und y liegt. EXISTS ergibt TRUE wenn eine rechts angegebene Unterabfrage mindestens einen Datensatz ergibt. Sichten, Stored Procedures, Funktionen und Trigger 83 IN ergibt TRUE wenn der linke Operand in der rechts in Klammern angegebenen Menge liegt. LIKE ergibt TRUE wenn der linke Operand dem rechts angegebenen Zeichenkettenmuster (inklusive Wildcards) entspricht. NOT kehrt den Wert eines booleschen Ausdrucks um. OR ergibt TRUE wenn einer von zwei booleschen Ausdrücken TRUE ergibt. SOME wie All Tabelle 16: Die logischen TSQL-Operatoren A/A $ , & Häufig reicht innerhalb einer Stored Procedure eine einfache SELECT-Anweisung nicht aus. Dann können Sie einen Cursor verwenden, um zeilenweise durch die ermittelten Datensätze zu gehen. Sie deklarieren einen Cursor mit DECLARE cursor_name CURSOR [LOCAL | GLOBAL] [FORWARD_ONLY | SCROLL] [STATIC | KEYSET | DYNAMIC | FAST_FORWARD] [READ_ONLY | SCROLL_LOCKS | OPTIMISTIC] [TYPE_WARNING] FOR select_statement [FOR UPDATE [OF column_name [,...n]]] cursor_name definiert den Namen des Cursors. Mit dem Zusatz GLOBAL erreichen Sie, dass der Cursor auch von anderen Prozeduren verwendet werden kann (was allerdings nur für die Verbindung zum Server gilt, die die Prozedur aufgerufen hat). Mit FORWARD_ONLY definieren Sie, dass die Datensatzliste nur einmal vorwärts durchlaufen werden kann. Ein solcher Cursor benötigt weniger Systemressourcen. Mit STATIC | KEYSET | DYNAMIC | FAST_FORWARD geben Sie den Typ des Cursors an. Dieser entspricht im Wesentlichen den Cursortypen von ADO. Mit READ_ONLY | SCROLL_LOCKS | OPTIMISTIC geben Sie für Aktualisierungen an, wie Sie Ihre Datensatzliste sperren wollen. Die UPDATE-Optionen legt fest, ob er Cursor eine Aktualisierung zulässt. Sie können die aktualisierbaren Datenfelder mit UPDATE OF column_name einschränken. Normalerweise benötigen Sie wahrscheinlich seltener einen Cursor, der aktualisierbar ist. Sie sollten diese Möglichkeit jedoch im Auge behalten. Ein Cursor zum einfachen, schreibgeschützten Durchgehen der Customers-Tabelle wird z. B. folgendermaßen definiert: DECLARE curCustomers CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR SELECT CustomerID, CompanyName FROM Customers ORDER BY CustomerID Nachdem Sie den Cursor erzeugt haben, müssen Sie diesen noch öffnen: OPEN curCustomers Nach dem Öffnen können Sie die Datensätze mit FETCH durchgehen: Sichten, Stored Procedures, Funktionen und Trigger 84 FETCH [[NEXT | PRIOR | FIRST | LAST | ABSOLUTE {n | @nvar}| RELATIVE {n | @nvar}] FROM] {{[GLOBAL] cursor_name } | @cursor_variable_name} [INTO @variable_name[,...n] ] FETCH geht zum nächsten (FETCH NEXT), vorherigen (FETCH PRIOR), ersten (FETCH FIRST), letzten (FETCH LAST) oder zu einem Datensatz mit einer bestimmten Nummer (FETCH ABSOLUTE 10 z. B. zum 10. Datensatz) oder zu einem Datensatz relativ zum aktuellen (FETCH RELATIVE 5 z. B. 5 Datensätze weiter), Mit INTO @variable_name sorgen Sie dafür, dass die Datenfelder in Variablen geschrieben werden (die Sie natürlich zuvor deklarieren müssen). Um eine Datensatzliste durchzugehen, hilft Ihnen die globale Variable @@FETCH_STATUS. Diese nimmt nach einem FETCH die folgenden Werte an: @@FETCH_STATUS-Wert Bedeutung 0 Der letzte Fetch war erfolgreich. -1 Der letzte Fetch war nicht erfolgreich, da die Datensatzliste vor dem ersten oder nach dem letzten Datensatz steht. Es ist kein Datensatz aktuell. -2 Der letzte Fetch war nicht erfolgreich, da der aktuelle Datensatz (von einem anderen Benutzer) zwischenzeitlich gelöscht wurde. Tabelle 17: Werte des Fetch-Status Nach dem Auswerten schließen Sie den Cursor und geben den reservierten Speicher frei: CLOSE curCustomers DEALLOCATE curCustomers Das folgende Beispiel zeigt einen einfachen Fetch. Dabei wird die nächsten freie KundenNummer in einer Kunden-Tabelle ermittelt, deren Kunden-Nummer nicht automatisch (über eine Identity-Spalte) vergeben wird: CREATE PROCEDURE Get_Free_CustomerId(@StartId int) AS DECLARE @CustomerId int DECLARE @SearchId int SELECT @SearchId = @StartId DECLARE curCustomers CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR SELECT CustomerID FROM Customers WHERE CustomerID > @StartId ORDER BY CustomerID OPEN curCustomers FETCH NEXT FROM curCustomers INTO @CustomerID WHILE @@FETCH_STATUS = 0 BEGIN IF @CustomerID > @SearchId BEGIN CLOSE curCustomers DEALLOCATE curCustomers RETURN @SearchID END FETCH NEXT FROM curCustomers INTO @CustomerID SET @SearchId = @SearchId + 1 END CLOSE curCustomers DEALLOCATE curCustomers RETURN @SearchId Sichten, Stored Procedures, Funktionen und Trigger 85 A/D $ , 4 Stored Procedures können Sie wie Sichten sehr einfach über die ALTER-Anweisung verändern: ALTER PROCEDURE Get_Free_CustomerId(@StartId int) AS ... Wie schon bei Sichten ist der Vorteil dabei, dass der SQL Server Rechte, die auf die Stored Procedure gesetzt sind, beibehält. A8 2 Ab der Version 2000 erlaubt der SQL Server (endlich) auch die Erstellung von Funktionen. Funktionen, die ebenfalls in TSQL geschrieben werden, sind so etwas wie vereinfachte Stored Procedures, die aber im Gegensatz zu diesen beliebige Datentypen zurückgeben können. Einer Funktion können Argumente übergeben werden. SQL-Server-Funktionen gleichen damit den von der herkömmlichen Programmierung bekannten Funktionen. Funktionen können im SQL Server einfache Datentypen oder Datensatzlisten (in Form des table-Datentyps) zurückgeben. Da die Anwendung von Funktionen, die Datensatzlisten zurückgeben, eher speziell ist, verzichte ich in diesem Artikel auf eine nähere Beschreibung. A8 2 Funktionen können Sie ähnlich Stored Procedures über den FUNKTIONEN-Eintrag im Datenbank-Ordner des Enterprise Managers erstellen. Alternativ können Sie Funktionen auch direkt in SQL schreiben (was ja auch bei der Erstellung im Enterprise Manager notwendig ist). Funktionen, die einen einfachen Datentypen zurückgeben, werden nach dem folgenden Schema deklariert: CREATE FUNCTION [owner_name.]function_name ([{@parameter_name [AS] scalar_parameter_data_type [ = default ] } [ ,...n ] ] ) RETURNS scalar_return_data_type [ WITH < function_option> [ [,] ...n] ] [ AS ] BEGIN function_body RETURN scalar_expression END Bei der Deklaration müssen Sie angeben, welche Argumente die Funktion besitzt und welchen Datentyp diese zurückliefert. Innerhalb der Funktion können Sie mit TSQL programmieren. Am Ende der Funktion geben Sie das Ergebnis mit RETURN zurück. Sichten, Stored Procedures, Funktionen und Trigger 86 So können Sie z. B. in der Northwind-Datenbank eine Funktion schreiben, die den Gesamtumsatz eines Kunden ermittelt und zurückgibt: CREATE FUNCTION GetCustomerSales(@CustomerId nvarchar(5)) RETURNS money AS BEGIN /* Variable für den Umsatz */ DECLARE @Sales money /* Abfrage der Umsatzdaten */ SELECT @Sales = SUM([Order Details].UnitPrice * [Order Details].Quantity) FROM [Order Details] INNER JOIN Orders ON [Order Details].OrderId = Orders.OrderId WHERE Orders.CustomerId = @CustomerId /* Rückgabe */ RETURN @Sales END Diese Funktion können Sie nun in jeder SQL-Anweisung einsetzen. Als Argument können Sie konstante Daten, Variablen oder auch die Inhalte von Tabellenfeldern übergeben. Lediglich der Datentyp der übergebenen Daten muss zum Argument passen. Den Rückgabewert können Sie in SELECT-Abfragen ausgeben oder in Variablen speichern. Das folgende Beispiel ruft die Funktion für einen spezifischen Kunden auf: SELECT dbo.GetCustomerSales('ALFKI') AS Sales Beachten Sie, dass Sie beim Aufruf von Funktionen den Besitzer immer mit angeben müssen. Das Ergebnis ist eine einfache Datensatzliste mit einem Datensatz und einer Spalte Sales: Sales --------------------4596.2000 Das nächste Beispiel fragt einige Kundendaten ab und verwendet die Funktion zur Ermittlung des Umsatzes des jeweiligen Kunden: SELECT CustomerId, CompanyName, City, dbo.GetCustomerSales(CustomerId) AS Sales FROM Customers Das Ergebnis (Auszug): CustomerId ---------ALFKI ANATR ANTON ... WILMK WOLZA A8" CompanyName ---------------------------------------Alfreds Futterkiste Ana Trujillo Emparedados y helados Antonio Moreno Taquería City --------------Berlin México D.F. México D.F. Sales ---------4596.2000 1402.9500 7515.3500 Wilman Kala Wolski Zajazd Helsinki Warszawa 3161.3500 3531.9500 2 4 Funktionen können Sie ähnlich Stored Procedures und Sichten über die ALTER-Anweisung verändern: ALTER FUNCTION GetCustomerSales(@CustomerId nvarchar(5)) RETURNS money AS ... Sichten, Stored Procedures, Funktionen und Trigger 87 A9 5 Trigger ähneln auch wieder Stored Procedures. Sie sind wie diese in TSQL geschrieben und verwenden dieselben Programmstrukturen. Die Unterschied sind, dass Trigger keine Parameter besitzen können und keine Werte zurückgeben, und dass Trigger nicht explizit aufgerufen werden, sondern implizit immer dann, wenn auf einer Tabelle Datensätze angefügt, geändert oder gelöscht werden. Ein Trigger ist immer fest mit einer Tabelle verbunden und bezieht sich dort auf eine UPDATE-, INSERT- oder DELETE-Aktion oder eine Kombination dieser Aktionen. Trigger werden verwendet, um: • referentielle Integrität da zu gewährleisten, wo die eingebaute Referentielle Integrität des SQL Servers nicht ausreicht; • Spalten mit laufenden Summen zu aktualisieren; • Spalten zu aktualisieren, die berechnete Werte beinhalten; • externe Vorgänge anzustoßen, wie zum Beispiel das Senden einer E-Mail bei einer bestimmten Aktion. Auf einer Tabelle können mehrere Trigger für eine bestimmte Aktion (INSERT, UPDATE oder DELETE) definiert werden. Dabei müssen Sie beachten, dass die Reihenfolge dieser Trigger nicht festgelegt werden kann. A9 5 Einen Trigger erzeugen Sie im Enterprise Manager über das Kontextmenü einer Tabelle über den Befehl ALLE TASKS / TRIGGER VERWALTEN: Abbildung 39: Der Dialog zur Verwaltung von Triggern mit einem neuen Trigger auf der Kunden-Tabelle Sichten, Stored Procedures, Funktionen und Trigger 88 A9" , 5 In einem Trigger stehen ihnen die speziellen logischen Tabellen inserted und deleted zur Verfügung. inserted enthält bei einem Anfüge-Trigger alle angefügten Datensätze und bei einem Aktualisierungs-Trigger alle geänderten Datensätze in dem Zustand nach der Änderung. deleted enthält bei einem Lösch-Trigger alle gelöschten Datensätze und bei einem Aktualisierungs-Trigger alle geänderten Datensätze vor der Änderung. Diese beiden Tabellen können in Abfragen genauso verwendet werden wie normale Tabellen mit dem Unterschied, dass eine Aktualisierung dieser Tabellen nicht möglich ist. 5 Das folgende Beispiel implementiert einen Trigger, der beim Anfügen eines Bestelldetails das (neue) Feld Order Sum der Bestellung aktualisiert. Ein solches Feld, das immer die Gesamt-Summe der Bestellung speichern soll, ist natürlich redundant und widerspricht den Regeln der Normalisierung. Die Gesamtsumme einer Bestellung kann schließlich auch über eine Abfrage der Bestelldetails ermittelt werden. In großen Datenbanken führt der dazu notwendige Join inklusive der eventuell notwendigen Gruppierung aber zu einer sehr schlechten Performance. Die Verwaltung der Bestell-Gesamtsumme im separaten Feld bringt also in vielen Fällen eine erhebliche Performance-Steigerung. Und das ist das, was den Endanwender interessiert. Die Trigger, die wir hier entwickeln, kümmern sich um das automatische Aktualisieren. Das redundante Feld führt also zu keinerlei Pflege-Aufwand. Um dieses Beispiel nachvollziehen zu können, müssen Sie der Tabelle Orders in der Northwind-Datenbank zunächst das Feld Order Sum hinzufügen: ALTER TABLE Orders ADD [Order Sum] money NOT NULL DEFAULT 0 Dann können Sie den Trigger erzeugen: CREATE TRIGGER Order_Details_I_Trig ON [Order Details] FOR INSERT AS /* Variable für die Summe */ DECLARE @Sum money /* Summe der neuen Bestelldetails ermitteln (das können in einem Trigger beim Hinzufügen durchaus auch mehrere sein, z. B. wenn Bestelldetails über die Abfrage einer anderen Tabelle hinzugefügt wurden) */ SELECT @Sum = Sum(UnitPrice * Quantity) FROM inserted /* Summe in der Bestellung ablegen. Dazu wird zunächst die Bestellnummer ermittelt */ DECLARE @OrderId int SELECT @OrderId = OrderId FROM inserted /* Summe speichern */ UPDATE Orders SET [Order Sum] = [Order Sum] + @Sum WHERE OrderId = @OrderId Der Trigger ist allerdings nicht perfekt. Wenn über eine SELECT-INTO-Anweisung mehrere Bestelldetails aus einer anderen Tabelle heraus in die Tabelle Order Details geschrieben werden und diese unterschiedlichen Bestellungen angehören, wird deren Gesamtsumme lediglich in eine der Bestellungen geschrieben. Sichten, Stored Procedures, Funktionen und Trigger 89 Dieses Problem zu lösen ist nicht einfach. Sie können die inserted-Tabelle über einen Cursor Datensatz für Datensatz durchgehen um jede einzelne Bestellung zu aktualisieren: CREATE TRIGGER Order_Details_I_Trig ON [Order Details] FOR INSERT AS /* inserted-Tabelle über einen Cursor Datensatz für Datensatz durchgehen */ DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR SELECT OrderId, UnitPrice, Quantity FROM inserted OPEN cur /* Variablen für die Bestellnummer und die Summe der Detailbestellung */ DECLARE @OrderId nvarchar(5) DECLARE @UnitPrice money DECLARE @Quantity int /* Cursor durchgehen */ FETCH NEXT FROM cur INTO @OrderId, @UnitPrice, @Quantity WHILE @@FETCH_STATUS = 0 BEGIN /* Summe in der Bestellung ablegen */ UPDATE Orders SET [Order Sum] = [Order Sum] + (@UnitPrice * @Quantity) WHERE OrderId = @OrderId /* Nächste Position */ FETCH NEXT FROM cur INTO @OrderId, @UnitPrice, @Quantity END Dieser Trigger aktualisiert nun bei jedem Hinzufügen eines Bestelldetails die Gesamtsumme in der Bestellung. Das folgende Beispiel erstellt eine neue Bestellung und fragt am Ende die Bestellsumme ab: /* Bestellung hinzufügen */ INSERT INTO Orders (CustomerId, OrderDate) VALUES ('ALFKI', GETDATE()) /* Die automatisch erzeugte OrderId ermitteln */ DECLARE @OrderId int SELECT @OrderId = MAX(OrderId) FROM Orders /* Bestelldetails hinzufügen */ DECLARE @ProductId int DECLARE @UnitPrice money DECLARE @Quantity int SET @ProductId = 1 SET @Quantity = 100 SELECT @UnitPrice = UnitPrice FROM Products WHERE ProductId = @ProductId INSERT INTO [Order Details] (OrderId, ProductId, UnitPrice, Quantity) VALUES (@OrderId, @ProductId, @UnitPrice, @Quantity) SET @ProductId = 2 SET @Quantity = 10 SELECT @UnitPrice = UnitPrice FROM Products WHERE ProductId = @ProductId INSERT INTO [Order Details] (OrderId, ProductId, UnitPrice, Quantity) VALUES (@OrderId, @ProductId, @UnitPrice, @Quantity) SET @ProductId = 3 SET @Quantity = 55 SELECT @UnitPrice = UnitPrice FROM Products WHERE ProductId = @ProductId INSERT INTO [Order Details] (OrderId, ProductId, UnitPrice, Quantity) VALUES (@OrderId, @ProductId, @UnitPrice, @Quantity) /* Bestellung abfragen */ SELECT OrderId, [Order Sum] FROM orders WHERE orderId = @OrderId Sichten, Stored Procedures, Funktionen und Trigger 90 5 Nun müssen Sie noch einen Trigger implementieren, der auf ein Aktualisieren der für die Berechnung wichtigen Spalten reagiert. Dieser Trigger fragt die Tabelle inserted nach den neuen Daten und die Tabelle deleted nach den alten Daten ab um den neuen Bestellwert korrekt ermitteln zu können. In Aktualisierungs-Triggern ist es oft notwendig, zu erkennen, welche Spalten aktualisiert wurden. So muss ein Trigger, der die Aktualisierung der Primärschlüsselspalte in einer Mastertabelle an alle in Beziehung stehenden Detailtabellen weitergibt, erkennen, ob die Primärschlüsselspalte geändert wurde. Sie können dies sehr einfach über die UPDATE-Funktion ermitteln, wie Sie im Beispiel sehen: CREATE TRIGGER Order_Details_U_Trig ON [Order Details] FOR UPDATE AS IF UPDATE(UnitPrice) OR UPDATE(Quantity) /* Wenn überhaupt eine der relevanten Spalten geändert wurde */ BEGIN /* inserted-Tabelle über einen Cursor Datensatz für Datensatz durchgehen */ DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR SELECT OrderId, ProductId, UnitPrice * Quantity AS DetailSum FROM inserted OPEN cur /* Variablen für die Bestellnummer und die Summe der Detailbestellung */ DECLARE @OrderId nvarchar(5) DECLARE @ProductId int DECLARE @SumNew money DECLARE @SumOld money /* Cursor durchgehen */ FETCH NEXT FROM cur INTO @OrderId, @ProductId, @SumNew WHILE @@FETCH_STATUS = 0 BEGIN /* Ermitteln des alten Werts aus der deleted-Tabelle */ SELECT @SumOld = UnitPrice * Quantity FROM deleted WHERE OrderId = @OrderId AND ProductId = @ProductId /* Summe in der Bestellung aktualisieren */ UPDATE Orders SET [Order Sum] = [Order Sum] - @SumOld + @SumNew WHERE OrderId = @OrderId /* Nächste Position */ FETCH NEXT FROM cur INTO @OrderId, @ProductId, @SumNew END END Nun können Sie ohne Probleme auch Bestelldetails aktualisieren. Die Bestellsumme wird automatisch aktualisiert: UPDATE [Order Details] SET UnitPrice = UnitPrice * 0.9 WHERE OrderId = 1001 Sichten, Stored Procedures, Funktionen und Trigger 91 =, 5 In unserem Beispiel müssen Sie natürlich noch auf das Löschen von Bestelldetails reagieren. Dazu implementieren Sie einen Lösch-Trigger, der die deleted-Tabelle durchgeht und die darin enthaltene Bestellsumme von der Gesamt-Bestellsumme abzieht: CREATE TRIGGER Order_Details_D_Trig ON [Order Details] FOR DELETE AS /* deleted-Tabelle über einen Cursor Datensatz für Datensatz durchgehen */ DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR SELECT OrderId, UnitPrice * Quantity AS DetailSum FROM deleted OPEN cur /* Variablen für die Bestellnummer und die Summe der Detailbestellung */ DECLARE @OrderId nvarchar(5) DECLARE @Sum money /* Cursor durchgehen */ FETCH NEXT FROM cur INTO @OrderId, @Sum WHILE @@FETCH_STATUS = 0 BEGIN /* Summe in der Bestellung aktualisieren */ UPDATE Orders SET [Order Sum] = [Order Sum] - @Sum WHERE OrderId = @OrderId /* Nächste Position */ FETCH NEXT FROM cur INTO @OrderId, @Sum END Nun müsste die Bestellsumme, die in den Bestellungen verwaltet wird, immer korrekt sein. Vor den Triggern bereits vorhandene Bestellungen müssen Sie allerdings noch »von Hand« aktualisieren. Dabei müssen Sie beachten, dass eine Bestellung auch keine Bestelldetails besitzen kann. Ich löse das Problem über eine Unterabfrage und die ISNULL-Funktion: UPDATE Orders SET [Order Sum] = (SELECT ISNULL(SUM(UnitPrice * Quantity), 0) FROM [Order Details] WHERE [Order Details].OrderId = Orders.OrderId) 5 5 Gerade bei Triggern, die ja immer automatisch aufgerufen werden, ist das Testen der Funktion extrem wichtig. Bei unseren Beispieltriggern können Sie dazu einfach eine Bestellung erzeugen, ändern und Bestelldetails wieder löschen, um die korrekte Funktion zu ermitteln: /* Bestellung hinzufügen */ INSERT INTO Orders (CustomerId, OrderDate) VALUES ('ALFKI', GETDATE()) /* Die automatisch erzeugte OrderId ermitteln */ DECLARE @OrderId int SELECT @OrderId = MAX(OrderId) FROM Orders /* Bestelldetails hinzufügen */ DECLARE @ProductId int DECLARE @UnitPrice money DECLARE @Quantity int SET @ProductId = 1 SET @Quantity = 100 SELECT @UnitPrice = UnitPrice FROM Products WHERE ProductId = @ProductId INSERT INTO [Order Details] (OrderId, ProductId, UnitPrice, Quantity) VALUES (@OrderId, @ProductId, @UnitPrice, @Quantity) Sichten, Stored Procedures, Funktionen und Trigger 92 SET @ProductId = 2 SET @Quantity = 10 SELECT @UnitPrice = UnitPrice FROM Products WHERE ProductId = @ProductId INSERT INTO [Order Details] (OrderId, ProductId, UnitPrice, Quantity) VALUES (@OrderId, @ProductId, @UnitPrice, @Quantity) SET @ProductId = 3 SET @Quantity = 55 SELECT @UnitPrice = UnitPrice FROM Products WHERE ProductId = @ProductId INSERT INTO [Order Details] (OrderId, ProductId, UnitPrice, Quantity) VALUES (@OrderId, @ProductId, @UnitPrice, @Quantity) /* Bestellung abfragen */ SELECT OrderId, [Order Sum] FROM Orders WHERE OrderId = @OrderId /* Bestellung ändern */ UPDATE [Order Details] SET Quantity = 100 WHERE OrderId = @OrderId AND ProductId = 2 /* Bestellung abfragen */ SELECT OrderId, [Order Sum] FROM Orders WHERE OrderId = @OrderId /* Ein Bestelldetail löschen */ DELETE FROM [Order Details] WHERE OrderId = @OrderId AND ProductId = 2 /* Bestellung abfragen */ SELECT OrderId, [Order Sum] FROM Orders WHERE OrderId = @OrderId Wenn die Trigger korrekt ausgeführt werden, gibt die erste Abfrage nach dem Hinzufügen die Summe 2540 zurück, die zweite (nach dem Ändern eines Bestelldetails) die Summe 4060 und die dritte (nach dem Löschen eines Bestelldetails) die Summe 2728. Wenn Ihre Trigger nicht zuverlässig arbeiten, müssen Sie wohl debuggen, wie ich es in Kapitel 8.6 beschreibe. A9/ + , 5 Ein Trigger wird immer nach der Aktion ausgelöst, die den Trigger aufgerufen hat. Bei einem Lösch-Trigger zum Beispiel sind die Datensätze zum Zeitpunkt der Ausführung des Triggers bereits gelöscht, wobei das Löschen allerdings in einer Transaktion ausgeführt wird. Dasselbe gilt natürlich für Aktualisierungs- und Anfüge-Trigger. Innerhalb des Triggers können Sie die Aktion, die den Trigger aufgerufen hat, durch ein einfaches ROLLBACK rückgängig machen. Das folgende Beispiel implementiert einen Trigger, der eine Veränderung der Verleihe-Tabelle am Ende eines Monats (wenn der Monatsbericht geschrieben wird) verhindert: CREATE TRIGGER Verleihe_DIU_Trig ON Verleihe FOR DELETE, INSERT, UPDATE AS IF DAY(GETDATE()) >= 28 BEGIN ROLLBACK DECLARE @Error nvarchar(255) SET @Error = 'Am Monatsende kann kein Verleih aufgenommen, ' + 'verändert oder gelöscht werden' RAISERROR(@Error, 16, 1) END Dieses Beispiel verwendet die RAISERROR-Funktion zur Erzeugung eines benutzerdefinierten Fehlers. Am ersten Argument wird der Fehlertext übergeben. Im Beispiel wird eine Variable für den Fehlertext verwendet, weil TSQL das Umbrechen eines Zeichenketten-Literals am ersten Argument der RAISERRORFunktion (eigenartigerweise) nicht unterstützt. Am zweiten Argument übergeben Sie den Schweregrad (16 = „normaler“ Fehler, nicht kritisch) des Fehlers und am dritten einen Statuswert. Sichten, Stored Procedures, Funktionen und Trigger 93 A98 * 4 5 Trigger können Sie wie Stored Procedures, Sichten und Funktionen über die ALTER-Anweisung verändern. A: $ 5 2 , 7 Das Debuggen von Stored Procedures, Funktionen und Triggern ist ein wichtiger Prozess, wenigstens dann, wenn diese Fehler beinhalten (was bei mir recht häufig der Fall ist ). Stored Procedures, Funktionen und Trigger können Sie über verschiedene Debugger auf Fehler untersuchen. Microsoft stellt für TSQL-Programme den TSQL-Debugger zur Verfügung, der Bestandteil der SQL-Server-2000-Client-Tools und der Enterprise-Edition von Visual Studio 6 ist. Alternativ können Sie auch den Debugger von Visual Studio .NET verwenden. Im Folgenden beschreibe ich, wie Sie den TSQL-Debugger und den Debugger von Visual Studio .NET grundsätzlich einsetzen. Sie sollten beim Debuggen beachten, dass Sie dieses nach Möglichkeit niemals in einem SQL Server ausführen sollten, der in der Produktion eingesetzt wird. Beim Debuggen wird der Server zum einen in einen speziellen Zustand versetzt, der das Debuggen überhaupt erst ermöglicht und der den Server verlangsamt. Zum anderen kann es immer vorkommen, dass der Debugging-Vorgang nicht korrekt abgeschlossen und das System deshalb in der Folge nur sehr träge ausgeführt wird oder sogar irgendwann abstürzt. Debuggen Sie wenn möglich immer mit einer Kopie der Datenbank auf einem separaten SQL Server. A: 0 * Damit Sie debuggen können, müssen auf dem SQL Server dessen Debugging-Komponenten installiert sein. Holen Sie dies gegebenenfalls über die SQL-Server-Installation nach, indem Sie diese normal starten und im sechsten Schritt die Option wählen, dass Sie »eine vorhandene Instanz von SQL Server aktualisieren« wollen. Übergehen Sie die nächsten zwei Schritte, geben Sie bei der Auswahl der zu installierenden Komponenten unter ENTWICKLUNGSTOOLS die DEBUGGERSCHNITTSTELLE an und schließen Sie die Installation ab. ! E Auf direktem Wege können Sie nur Stored Procedures debuggen. In einigen Debuggern führen Sie diese dazu über den Debugger aus, andere Debugger wie der von Visual Studio .NET erlauben darüber hinaus auch das Setzen von Haltepunkten, an denen der Debugger die Prozedur automatisch anhält. Damit können Sie Stored Procedures auch dann debuggen, wenn ein in Visual Studio .NET ausgeführtes Programm diese ausführt. Prinzipiell können Sie also • im Query Analyzer oder in Visual Studio debuggen, indem Sie eine Stored Procedure dort über den Debugger direkt aufrufen, • in Visual Studio debuggen, indem Sie in einer Stored Procedure oder Funktion einen Haltepunkt setzen und ein, ebenfalls in Visual Studio geöffnetes (Visual Basic-, C#- etc.) Anwendungs-Projekt ausführen das die Stored Procedure oder die Funktion direkt oder indirekt aufruft. Sichten, Stored Procedures, Funktionen und Trigger 94 Wenn Sie im Query Analyzer oder in Visual Studio ohne Ausführung eines Programms eine Funktion debuggen wollen, müssen Sie eine Dummy-Stored Procedure schreiben, die diese Funktion aufruft und die Stored Procedure ausführen. Über das im Debugger mögliche schrittweise Weitergehen können Sie dann in die Funktion verzweigen. Zum direkten Debuggen eines Triggers müssen Sie ebenfalls eine Dummy-Stored Procedure schreiben. Diese muss irgendeine SQL-Aktion ausführen, die den Trigger auslöst. Über das schrittweise Weitergehen in der Stored Procedure können Sie dann wie bei einer Funktion in den Trigger verzweigen. A:" # Als Beispiel zum Debugging verwende ich eine Funktion und eine Stored Procedure, die diese Funktion aufruft. Die Funktion soll (weil mir einmal wieder nichts weiter einfällt ...) ermitteln ob eine Zahl eine Primzahl ist. Die Stored Procedure soll alle Produkte einer anzugebenden Kategorie durchgehen, deren Produktnummer eine Primzahl ist und den Preis dieser Produkte um einen anzugebenden Prozentwert erhöhen. Das Beispiel ist zwar eigentlich sinnlos, aber zum Debuggen recht gut geeignet. Die Funktion enthält einen Fehler (welcher das ist, soll das Debuggen klären): CREATE FUNCTION IsPrimeNumber(@Number int) RETURNS bit AS BEGIN DECLARE @Divisor int SET @Divisor = 1 WHILE @Divisor < @Number BEGIN IF @Number % @Divisor = 0 BEGIN /* Die Zahl lässt sich ohne Rest teilen und ist folglich keine Primzahl */ RETURN 0 END SET @Divisor = @Divisor + 1 END /* Wenn die Funktion hier ankommt ist die Zahl keine Primzahl */ RETURN 1 END Die Stored Procedure ruft die Funktion auf: CREATE PROCEDURE Update_PrimeNumber_Product_Price (@CategoryId int, @Factor real) AS UPDATE Products SET UnitPrice = UnitPrice * @Factor WHERE CategoryId = @CategoryId AND dbo.IsPrimeNumber(ProductId) = 1 Leider funktioniert die Stored Procedure nicht. Bei allen Tests wird kein Produkt aktualisiert. Sie müssen also debuggen. Sichten, Stored Procedures, Funktionen und Trigger 95 A:/ 5$- Den TSQL-Debugger können Sie sehr einfach über den Query Analyzer aufrufen. Öffnen Sie dazu den Ordner GESPEICHERTE PROZEDUREN für die Datenbank im Query Analyzer. Abbildung 40: Der Ordner für gespeicherte Prozeduren im Query Analyzer Suchen Sie die Stored Procedure und wählen Sie im Kontextmenü des Eintrags den Befehl DEBUGGEN. Im erscheinenden Dialog können Sie die Parameterwerte definieren und die Prozedur starten. Abbildung 41: Dialog zum Starten des Debuggers Sichten, Stored Procedures, Funktionen und Trigger 96 Starten Sie die Prozedur dann über den AUSFÜHREN-Schalter. Der Debugger startet die Prozedur und hält diese an der ersten Anweisung an. Abbildung 42: Der Debugger hat die Prozedur gestartet und an der ersten Anweisung angehalten Über F11 können Sie nun jede Anweisung einzeln ausführen. F11 springt dabei in untergeordnet aufgerufene Funktionen oder Trigger hinein (was in unserem Fall gewünscht ist). Mit F10 könnten Sie eine Anweisung ausführen ohne dass der Debugger in untergeordnete Funktionen oder Trigger springt. Wenn Sie nun F11 betätigen, springt der Debugger in die Funktion. Sichten, Stored Procedures, Funktionen und Trigger 97 Abbildung 43: Der Debugger ist in die Funktion gesprungen Hier können Sie wieder mit F11 und F10 weitergehen um die Funktion zu debuggen. Im unteren Bereich zeigt der Debugger dabei immer die aktuellen Werte aller lokalen Variablen und der Parameter, einige wichtige globale Variablen und die Aufrufliste an. So können Sie sehr schnell herausfinden, wo der Fehler liegt. In unserem Fall erkennen Sie bei einem der Durchläufe, bei dem eine ProductId > 2 übergeben wird, dass die Schleife inkorrekt läuft. Diese beginnt nämlich bei 1 und nicht, wie es sein sollte, erst bei 2. Wenn Sie den Fehler gefunden haben, führen Sie die Stored Procedure dann mit F5 zu Ende aus, damit der Debugger diese wieder freigibt. Dieser Schritt ist sehr wichtig, da das System ansonsten in vielen Fällen bei weiteren Tests durcheinander gerät und »hängen bleibt« bzw. abstürzt, wenn der Debugger eine oder mehrere Stored Procedures aktuell noch angehalten hat. Sie sollten diesen Schritt auch ausführen, bevor Sie den Debugger schließen. . # Der TSQL-Debugger erlaubt auch das Setzen von Haltepunkten. Betätigen Sie auf einer Anweisung F9 um einen solchen zu setzen. Haltepunkte werden nur aktiv wenn eine Stored Procedure gestartet wurde. Sie können diese aber verwenden, um das Programm ab der aktuellen Stelle über F5 weiter bis zum Haltepunkt auszuführen und dort weiter zu debuggen. Sichten, Stored Procedures, Funktionen und Trigger 98 A:8 * $ 3 5 Wenn Sie Visual Studio .NET besitzen, können Sie den Debugger dieser Entwicklungsumgebung zum einen verwenden um Stored Procedures, Funktionen und Trigger wie im Query Analyzer direkt zu debuggen. Zum anderen können Sie in Stored Procedures, Funktionen und Triggern Haltepunkte setzen, die dazu führen, dass der Debugger automatisch anhält, wenn diese über ein Programm ausgeführt werden, das Sie in Visual Studio .NET entwickeln und testen. ! , $- $ * $ 3 5 E Visual Studio .NET-Professional kann lediglich die Personal-Edition des SQL Servers debuggen. Visual Studio .NET-Enterprise ist in der Lage, mit der Standard- und die EnterpriseEdition zu arbeiten. Scheinbar ist es mit der Enterprise-Edition nicht möglich, die SQL-ServerPersonal-Edition zu debuggen. Wenigstens konnte ich mein Visual Studio .NET-EnterpriseEdition nicht dazu bewegen ... $ , Der direkte Aufruf ist sehr einfach. Suchen Sie die Stored Procedure dazu im Server-Explorer und wählen Sie im Kontextmenü des Eintrags den Befehl IN GESPEICHERTE PROZEDUR SPRINGEN. Falls der zu debuggende SQL Server nicht im Server-Explorer auftaucht können Sie über den Ordner DATENVERBINDUNGEN auch eine separate Verbindung zu einer SQL-Server-Datenbank aufbauen. Sichten, Stored Procedures, Funktionen und Trigger 99 Abbildung 44: Der Server-Explorer von Visual Studio .NET Im zunächst erscheinenden Dialog können Sie die Parameterwerte eingeben. Abbildung 45: Eingabe der Parameterwerte Nachdem Sie Ihre Eingabe bestätigt haben wird die Prozedur ausgeführt und an der ersten Anweisung angehalten. Sichten, Stored Procedures, Funktionen und Trigger 100 Abbildung 46: Der Debugger hat die Prozedur angehalten Ähnlich dem TSQL-Debugger können Sie nun mit F11 (Einzelschritt) und F10 (Prozedurschritt) schrittweise weitergehen. In den unteren Fenstern sehen Sie die lokalen Variablen. Zusätzlich können Sie über das ÜBERWACHEN-Register eigene Überwachungsausdrücke eingeben. Sehr interessant ist auch das Befehlsfenster, in dem Sie gültige TSQL-Ausdrücke eingeben und über Return ausführen können. Sie erhalten dann das Ergebnis des Ausdrucks und können so auch (neue) Varianten von Ausdrücken ausprobieren, die in dieser Form nicht in der Prozedur vorkommen. Betätigen Sie nun F11 um in die Funktion zu springen und diese zu debuggen. . # Wie der TSQL-Debugger erlaubt auch der Visual Studio .NET-Debugger das Setzen von Haltepunkten. Betätigen Sie auf einer Anweisung F9 um einen solchen zu setzen. Wenn Sie das Programm mit F5 weiter ausführen, hält der Debugger am gesetzten Haltepunkt an. Wie beim TSQL-Debugger sollten Sie das Programm vor dem Schließen des Debuggers immer mit F5 zu Ende ausführen um das System nicht in einen inkonsistenten Zustand zu versetzen. B 5$% 7 * $ In einigen Fällen reicht der direkte Aufruf einer Stored Procedure nicht aus um diese oder untergeordnet aufgerufene Funktionen oder Trigger zu debuggen. Dies ist z. B. dann der Fall, wenn ein TSQL-Programm eigentlich korrekt läuft, bei der Verwendung in einem mit Visual Sichten, Stored Procedures, Funktionen und Trigger 101 Studio geschriebenen Programmen aber fehlerhaft ausgeführt wird, weil ungültige oder unerwartete Parameter übergeben werden. Um in diesem Kontext zu debuggen, können Sie im TSQL-Programm einfach einen Haltepunkt setzen und das Visual Studio-Projekt ausführen. Wird im Programm eine Anweisung ausgeführt, die zur indirekten Ausführung des TSQL-Programms führt, hält der Debugger dieses am Haltepunkt an. Das folgende Beispiel implementiert eine einfache C#-Konsolenanwendung, die unsere Beispiel-Stored-Procedure ausführt: using System; using System.Data; using System.Data.SqlClient; namespace SP_Test { class Start { [STAThread] static void Main(string[] args) { /* Verbindung zur Northwind-Datenbank auf dem lokalen * SQL Server aufbauen */ SqlConnection con = new SqlConnection( "Server=(local);Database=Northwind;Trusted_Connection=Yes"); con.Open(); /* SqlCommand-Objekt zur Ausführung der * Stored Procedure erzeugen */ SqlCommand cmd = new SqlCommand("Update_PrimeNumber_Product_Price", con); /* Typ des Befehls definieren */ cmd.CommandType = CommandType.StoredProcedure; /* Parameter definieren */ cmd.Parameters.Add("@CategoryId", SqlDbType.Int); cmd.Parameters.Add("@Factor", SqlDbType.Real); /* Parameterwerte übergeben */ cmd.Parameters["@CategoryId"].Value = 2; cmd.Parameters["@Factor"].Value = 1.1; try { /* Stored Procedure aufrufen */ cmd.ExecuteNonQuery(); /* Erfolg melden */ Console.WriteLine("Prozedur erfolgreich ausgeführt"); } catch (Exception ex) { /* Fehler melden */ Console.WriteLine("Fehler bei der Ausführung der Prozedur: " + ex.Message); } /* Verbindung wieder schließen */ con.Close(); } } } Um die indirekt aufgerufene TSQL-Funktion (oder die Stored Procedure) beim Aufruf durch das Programm zu debuggen, öffnen Sie diese über den Befehl SKALAR WERTENDE FUNKTION BEARBEITEN im Kontextmenü des Eintrags der Funktion im Server-Explorer und setzen in Sichten, Stored Procedures, Funktionen und Trigger 102 dieser Funktion über F9 einen Haltepunkt. Führen Sie das C#-Programm dann über F5 aus, sollte der Debugger am Haltepunkt anhalten. Obwohl dies so in Newsgroups beschrieben wird, konnte ich mein Visual Studio. NET-Enterprise-Edition nicht dazu bewegen, an einem Haltepunkt in einer Stored Procedure oder Funktion anzuhalten. Möglicherweise lag das daran, dass ich die Personal-Edition des SQL Servers einsetzte. Sichten, Stored Procedures, Funktionen und Trigger 103 D D ! 5 $- $ 0 =F 5 # , # 0 =F E Wenn Sie die Größe des Transaktionsprotokolls fest einstellen wollen (oder aus Performancegründen müssen), sollten Sie der Empfehlung von Microsoft folgen und von 25% der Datenbankgröße als gutem Ausgangspunkt ausgehen. In der Praxis kann jedoch auch ein wesentlich größeres Transaktionsprotokoll erforderlich sein. Dummerweise kann kein Benutzer mehr mit der Datenbank arbeiten, wenn das Transaktionsprotokoll voll ist. Also: besser zu groß als zu klein. Der Windows-Performance-Monitor hilft Ihnen bei der Entscheidung, wie groß das Transaktionsprotokoll sein sollte, wenn Sie für dieses eine feste Größe eingestellt haben. In der Praxis wird es wahrscheinlich meist sinnvoller sein, die Größe des Transaktionsprotokolls nicht fest einzustellen, sondern dieses sich automatisch vergrößern zu lassen. Das Transaktionsprotokoll (bzw. der gefüllte Bereichs eines fest eingestellten Protokolls) wird mit der Zeit immer größer, wenn Sie die Datenbank gar nicht sichern oder lediglich Backups der Datenbank (nicht des Transaktionsprotokolls) ausführen. Dabei kann es in der Praxis vorkommen, dass die Datenbank vielleicht um die 50 MB Größe, das Transaktionsprotokoll aber mehr als 1 GB Größe besitzt. Irgendwann sprengt die Größe des Transaktionsprotokolls dann den freien Speicherplatz auf der Festplatte und die Datenbank wird in einen fehlerverdächtigen Zustand geschaltet (und funktioniert natürlich nicht mehr). Leider füllt sich das Transaktionsprotokoll unter bestimmten Umständen oft auch ohne erkenntlichen Grund. In meinen ersten Versuchen mit dem SQL Server mit einer Bestelldatenbank mit mehreren Hunderttausend Bestellungen war das Transaktionsprotokoll zeitweise (nach mehreren Massenkopier- und Updateaktionen ohne das mir damals noch nicht bekannte Massenprotokollierte Wiederherstellungsmodell) mit mehr als 250 MB gefüllt, obwohl die Datenbank nur etwa 60 MB groß war. Microsoft beschreibt im MSDN die Gründe für das Auffüllen des Transaktionsprotokolls, die sehr komplex sein können. Einer der Hauptgründe für das Auffüllen des Transaktionsprotokolls ist, dass bei einem vollen oder differentiellen Backup der Datenbank das Transaktionsprotokoll nicht geleert wird. Damit wird Ihnen ermöglicht, dass Sie an Hand der im Transaktionsprotokoll aufgezeichneten Aktionen einen Zustand wiederherstellen können, der vor dem letzten Backup der Datenbank lag. Auch wenn Sie die Datenbank jeden Tag vollständig sichern, bleiben also alle Transaktionen im Transaktionsprotokoll erhalten. Wenigstens so lange, bis Sie dieses sichern. Erst das Backup des Transaktionsprotokolls nämlich entfernt die aufgezeichneten Transaktionen aus diesem. Ein Backup des Transaktionsprotokolls bewirkt, dass alle abgeschlossenen Transaktionen, die zum Zeitpunkt des Backups bereits in die Datenbank geschrieben wurden, im Transaktionsprotokoll abgeschnitten werden. Das Transaktionsprotokoll wird dadurch also verkleinert. Für den täglichen Normalbetrieb ist also ein regelmäßiges Backup des Transaktionsprotokolls die beste Voraussetzung dafür, dass dieses nicht zu groß wird. Dies führt bei einem automatisch vergrößerten Transaktionsprotokoll aber nicht dazu, dass die Datei auch gleich verkleinert wird. Der SQL Server belässt die Datei bei ihrer Größe und reserviert damit Speicherplatz für zukünftige Transaktionen. Wenn Sie allerdings die Datenbank und das Transaktionsprotokoll regelmäßig sichern (wie ich es im folgenden Abschnitt beschreibe), wird das Transaktionsprotokoll unter normalen Umständen nicht allzu groß werden. Manchmal treten leider aber auch nicht normale Umstände auf. Das ist z. B. dann der Fall, wenn eine grone Anzahl von Daten angefügt, gelöscht oder geändert werden (ohne dazu die BuklCopy-Funktion zu nutzen, die das Transaktionsprotokoll umgeht). In diesem Fall kann das Transaktionsprotokoll sehr groß werden und den Betrieb des SQL Servers gefährden. Dann Administrieren des SQL Servers 104 sollten Sie selbst Hand anlegen (oder dies über einen Auftrag im SQL Server Agent, der weiter unten beschrieben wird, automatisch ausführen lassen wenn das Transaktionsprotokoll häufiger zu groß wird). Beachtung verdient in diesem Zusammenhang auch das einfache Wiederherstellungs-Modell, das Sie für eine Datenbank einstellen können. Mit diesem Modell wird das Transaktionsprotokoll immer dann abgeschnitten, wenn ein Prüfpunkt auftritt, was (je nach Einstellung) so etwa jede Minute der Fall ist. Bei einem Prüfpunkt schreibt der SQL Server alle geänderten Datenseiten, die noch nicht physikalisch geschrieben wurden, in die Datenbank. Man könnte der Meinung sein, diese Option wäre eine gute Alternative zu einem regelmäßigen Backup des Transaktionsprotokolls, um dieses in der Größe zu beschränken. Da der SQL Server in bestimmten Situationen nach einem Systemausfall zur Wiederherstellung der Datenbank jedoch auch Information über abgeschlossene, bereits geschriebene Transaktionen benötigt und Microsoft selbst diese Option nur für Testzwecke während der Entwicklung einer Datenbank beschreibt, sollten sie besser das vollständige Wiederherstellungsmodell verwenden und ein regelmäßiges Backup der Datenbank und des Transaktionsprotokolls ausführen. ># * Als Vorbereitung der Verkleinerung des Transaktionsprotokolls sollten Sie die Datenbankintegrität überprüfen und (automatisch) reparieren, was in SQL (am Beispiel einer Warenwirtschafts-Datenbank) mit der folgenden Anweisung ausgeführt wird: DBCC CHECKDB ('Warenwirtschaft') Damit werden u. a. alle unbenötigten, aber reservierten Speicherseiten und Zeilen im Index freigegeben. Dann sollten Sie die Datenbank sichern, was in SQL in einer einfachen Form (wieder am Beispiel einer Warenwirtschafts-Datenbank) folgendermaßen ausgeführt wird: BACKUP DATABASE Warenwirtschaft TO DISK='C:\Backups\Warenwirtschaft-Sicherung' Nun können Sie das Transaktionsprotokoll mit der folgenden Anweisung in eine Datei sichern: BACKUP LOG Warenwirtschaft TO DISK='C:\Backups\Warenwirtschaft-Log-Sicherung' Alternativ können Sie auf die Sicherung verzichten und die abgeschlossenen Transaktionen einfach abschneiden: BACKUP LOG Warenwirtschaft WITH TRUNCATE_ONLY Danach sollten Sie nach einer Microsoft-Empfehlung (support.microsoft.com/?id=272318) die Datenbank (noch einmal) komplett sichern. Ob dies notwendig ist, bezweifle ich, da Sie diese ja bereits vor dem Abschneiden der abgeschlossenen Transaktionen gesichert haben. Das endgültige Verkleinern übernimmt dann die folgende Anweisung, der Sie den logischen Dateinamen des Transaktionsprotokolls übergeben: DBCC SHRINKFILE (Warenwirtschaft_Log) Administrieren des SQL Servers 105 D" , # + Microsoft empfiehlt, eine Unternehmensdatenbank einmal wöchentlich und deren Transaktionsprotokoll täglich zu sichern. Die so erzeugte Backups sollten auf einem Sicherungsmedium (z. B. einem Dat-Streamer) gesichert werden. Alle TransaktionsprotokollBackups sollten über zwei Wochen aufgehoben werden; alle Datenbank-Backups über zwei Monate. Abweichend von diesem Schema sollte die Datenbank in den folgenden Fällen gesichert werden: • direkt nach der Erzeugung. • nach jeder unprotokollierten Operation (z. B. Massenkopieren mit der Option ‚select into/bulk copy‘). • nach der Erzeugung von neuen Datenbankobjekten (Tabellen, Views, Indizes etc.). Die master-Datenbank sollte nach jeder Änderung der Struktur einer Datenbank und nach jeden Hinzufügen bzw. Entfernen von Datenbanken ebenfalls gesichert werden. Die msdb-Datenbank sollte nach jeder Änderung der Aufgaben des SQL Server Agent gesichert werden. Verwechseln Sie Backup und Restore nicht mit dem automatischen Wiederherstellen (Recovering) von Datenbanken nach einem Serverausfall. Nach einem Serverausfall stellt der SQL Server die Datenbanken mit Hilfe des Transaktionsprotokoll automatisch wieder her ohne ein Backup zu verwenden. Das Backup der Datenbanken ist wichtig für den Fall, dass • das System aufgrund eines Stromausfalls ausfällt und Dateien beschädigt werden, • eine Festplatte ausfällt, • das Betriebssystem ausfällt, • eine Anwendung fehlerhaft arbeitet und die Datenbank beschädigt (z. B. Datensätze löscht), • ein Benutzer fehlerhafte Eingaben macht oder aus Versehen Datensätze löscht. Theoretisch müsste es ausreichen, die Datenbank- und TransaktionsprotokollDateien über eine externe Backup-Software regelmäßig zu sichern und im Fehlerfall diese Dateien vom Sicherungsmedium zurückzuholen. In der Praxis ist dieses Vorgehen jedoch nicht praktikabel, da die vom SQL Server verwendeten Dateien nur dann überschrieben werden können, wenn diese nicht in Benutzung sind, d.h., wenn der SQL Server nicht läuft. Ein Backup und Restore über den SQL Server kann jedoch ausgeführt werden, auch wenn der SQL Server zurzeit in Benutzung ist. Diese Aufgaben können Sie von Hand vornehmen. Für den täglichen Betrieb sollten Sie diese Aufgaben jedoch dem Agenten überlassen, der weiter unten beschrieben wird. Administrieren des SQL Servers 106 D" ! Der SQL Server 2000 unterstützt drei Wiederherstellungs-Modelle, die ich im Abschnitt 5.1 bereits beschrieben habe. Sie müssen eines dieser Modelle in den Datenbankoptionen einstellen, damit Sie eine zu Ihrer Datenbank passende Backupstrategie umsetzen können. , ! Im einfachen Modell wird das Transaktionsprotokoll bei einem Prüfpunkt einfach abgeschnitten. Dabei wird der Speicherplatz der Transaktionen, die bereits in die Datenbank geschrieben wurden, freigegeben. Da das Transaktionsprotokoll beim einfachen Modell nur die aktiven Transaktionen beinhaltet, bringt das Backup dieses Protokolls nichts und wird deswegen auch nicht ermöglicht. Sie können im einfachen Modell lediglich ein Backup und Restore der Datenbankdateien (vollständig und differentiell) ausführen, nicht des Transaktionsprotokolls. Tritt ein Fehler nach einem Backup auf, sind alle Änderungen zwischen dem Backup und dem Fehlerzeitpunkt verloren. Das einfache Modell bringt den »Vorteil« mit, dass das Transaktionsprotokoll nicht sehr groß werden kann. Der Nachteil ist, dass Sie erweiterte Backup-Strategien, die das Transaktionsprotokoll mit einbeziehen, nicht anwenden können. 4 ! Das vollständige Wiederherstellungs-Modell belässt alle Transaktionen im Transaktionsprotokoll bis dieses oder die Datenbank gesichert wird (erst dann werden die inaktiven Transaktionen abgeschnitten). Es ermöglicht damit ein Sichern der Datenbank (vollständig und differentiell) und ein separates Sichern des Transaktionsprotokolls. Dieses für die meisten größeren Datenbanken sinnvolle Modell erlaubt z. B. das Sichern der gesamten Datenbank jeden Tag um 00:00 und das Sichern des (kleineren und damit schneller gesicherten) Transaktionsprotokolls jede Stunde. Damit ist die Wahrscheinlichkeit sehr gering, dass bei einem Crash des Servers viele Änderungen verloren gehen. # ! Dieses dem vollständigen Modell ähnliche Modell führt dazu, dass bestimmte Massenänderungen an den Daten (z. B. über SELECT INTO) nur minimal protokolliert werden. Damit werden diese Massenoperationen zwar performanter ausgeführt und benötigen weniger Speicherplatz im Transaktionsprotokoll. Beim einem Crash ist die Gefahr des Datenverlustes bezogen auf die in den Massenoperationen veränderten Daten aber sehr groß. Administrieren des SQL Servers 107 D"" , #$ Die richtige Backup-Strategie zu finden ist eine in der Praxis nicht einfache Aufgabe. Prinzipiell können Sie eine Datenbank nach den folgenden Schemen sichern: Einfaches Wiederherstellungsmodell: • Sichern der gesamten Datenbank in regelmäßigen Abschnitten; • Sichern der gesamten Datenbank in regelmäßigen Abschnitten; Sichern der Änderungen seit dem letzten Backup in kürzeren regelmäßigen Abschnitten (differentielles Backup). Vollständiges Wiederherstellungs-Modell: • Sichern der gesamten Datenbank in regelmäßigen Abschnitten; • Sichern der gesamten Datenbank in regelmäßigen Abschnitten; Sichern der Änderungen seit dem letzten Backup in kürzeren regelmäßigen Abschnitten. • Sichern der gesamten Datenbank in regelmäßigen Abschnitten; Transaktionsprotokolls in kürzeren regelmäßigen Abschnitten; • Sichern der gesamten Datenbank in regelmäßigen Abschnitten; Sichern der Änderungen seit dem letzten Backup in kürzeren regelmäßigen Abschnitten; Sichern des Transaktionsprotokolls in noch kürzeren regelmäßigen Abschnitten. Sichern des Dabei müssen Sie beachten, dass das Sichern der gesamten Datenbank sehr viel (Prozessor)Zeit und Ressourcen in Anspruch nimmt. Ein differentielles Sichern nimmt weniger (Prozessor-)Zeit und Ressourcen in Anspruch, das Sichern des Transaktionsprotokolls am wenigsten. Eine Datenbank, die recht intensiv genutzt wird, sollten Sie während der Nutzungszeit nicht vollständig und idealerweise auch nicht differentiell sichern. Idealerweise sichern Sie die Datenbank einmal täglich zu einem Zeitpunkt, an dem nur wenige oder keine Benutzer mit der Datenbank arbeiten. Dann sollten Sie zu gegebenen Zeitpunkten mit wenig Belastung (z. B. in den Betriebspausen) das Transaktionsprotokoll sichern. Das Ganze können Sie übrigens über den SQL Server Agent automatisieren, wie ich im Abschnitt 9.3 kurz beschreibe. Ein differentielles Backup ist bei dieser Strategie in meinen Augen nicht sinnvoll, es sei denn, Sie verwenden aus irgendwelchen Gründen das einfache Wiederherstellungsmodell. Administrieren des SQL Servers 108 D"/ , # . Das Backup einer Datenbank starten Sie von Hand über das Kontextmenü der Datenbank (ALLE TASKS / DATENBANK SICHERN). Abbildung 47: Der Dialog zum Backup einer Datenbank Die Option TRANSAKTIONSPROTOKOLL steht nur zur Verfügung wenn die Datenbank das vollständige Wiederherstellungsmodell verwendet und wenn Sie bereits zuvor ein Backup der Datenbankdatei(en) vorgenommen haben. Sie können die Datenbank vollständig oder differentiell sichern. Das vollständige Sichern speichert alle abgeschlossenen Transaktionen der gesamten Datenbank. Ein darauf folgendes differentielles Backup sichert lediglich die Änderungen seit dem letzten Vollbackup. Im Feld NAME können Sie einen Namen für die Sicherung eingeben, unter dem Sie alle Teile des Backups sichern können (Datenbankdateien, Transaktionsprotokolle). Unter diesem Namen können Sie ein Backup später vollständig wiederherstellen. Wählen Sie als Ziel FESTPLATTE aus, wenn Sie nicht auf Band sichern wollen. Fügen Sie dann über den HINZUFÜGEN-Schalter einzelne Dateien (in der Regel nur eine Datei) hinzu, in die das Backup geschrieben werden soll. Oben können Sie einstellen, ob sie die Datenbank komplett oder nur die Änderungen seit dem letzten Backup oder nur das Transaktionsprotokoll sichern wollen. Administrieren des SQL Servers 109 Bei der Vergabe des Dateinamens empfiehlt sich, das aktuelle Datum und eine Information mit in den Namen aufzunehmen, dass es sich dabei um ein Backup der Datenbankdatei (und nicht ges Transaktionsprotokolls) handelt. Nennen Sie die Datei z. B. Fahrradverleih_15.01.2003_Daten. Normalerweise (und genau das macht der SQL Server mit seinen Wartungsplänen auch) sollten Sie ein komplettes Backup der Datenbank in eine einzige Datei schreiben. Unten können Sie einstellen, ob das Backup an eine bereits vorhandene Datei gleichen Namens nur angehangen wird, oder ob diese Datei mit dem Backup überschrieben wird. Wenn Sie wie der SQL-Server-Wartungsplan vorgehen, erzeugen Sie pro Backup eine Datei, in deren Namen das Datum vorkommt und deren Name deswegen eindeutig ist. Wenn Sie die Option TERMINPLAN einschalten und einen Zeitplan eingeben, bedeutet das übrigens, dass dieses Backup als Job für den SQL Server Agent eingetragen wird. , # 5 # Schließen Sie das Backup der Datenbank nun ab. Ändern Sie danach einige Daten in der Datenbank, sodass der SQL Server das Transaktionsprotokoll wieder mit Transaktionen füllt. Wenn Sie dann den Backup-Dialog öffnen, können Sie auch das Transaktionsprotokoll sichern. Abbildung 48: Backup des Transaktionsprotokolls Administrieren des SQL Servers 110 Beachten Sie, dass Sie vor dem Backup den noch vom vorherigen Backup stehen gebliebenen Datei-Eintrag entfernen und einen neuen für das Transaktionsprotokoll einfügen. D"8 + Wiederherstellen können Sie eine Datenbank ähnlich dem Backup über das Kontextmenü der Datenbank. Der Enterprise Manager zeigt im Restore-Dialog alle aktuellen Backups an. Abbildung 49: Dialog zum Restore einer Datenbank Der Restore-Dialog listet die bisherigen Backups einer Datenbank auf, wenn Sie diese in der Liste SICHERUNGSKOPIEN DER FOLGENDEN DATENBANK ANZEIGEN auswählen. Tragen Sie den korrekten Namen der Datenbank in die obere Liste ein. Sie können eine Datenbank auch unter einem anderen Namen restaurieren, um z. B. Daten, die aus Versehen gelöscht wurden, in die originale Datenbank zurück zu kopieren. Für alle Backups können Sie in der Liste wählen, welche wiederhergestellt werden sollen. Die Reihenfolge wird vom SQL Server automatisch korrekt eingestellt. Sie sollten dabei aber darauf achten, dass Sie nicht ein Backup abwählen, das in der Mitte der zu restaurierenden Backups liegt, damit die Daten korrekt restauriert werden. Administrieren des SQL Servers 111 Dadurch dass Sie einige der letzten Transaktionsprotokoll-Sicherungen bzw. differentielle Datenbank-Sicherungen abwählen können, können Sie ein Backup auch nur bis zu einem bestimmten Zeitpunkt wiederherstellen. Diese Möglichkeit ist immer dann wichtig wenn ein Anwender aus »Versehen« Daten gelöscht oder fehlerhaft geändert hat. In diesem Fall können Sie die Datenbank in eine neue Datenbank (mit einem anderen Namen) zurücksichern und die geänderten Daten dann »von Hand« (über SQL) aus der wiederhergestellten in die aktuelle Datenbank zurückschreiben. Wenn Sie dazu SQL verwenden, geben Sie einfach den Datenbank- und den Besitzernamen vor den Tabellennamen an. Beispiel: Wiederherstellen der versehentlich gelöschten Produkte der Kategorie 1 aus einem in eine separate Datenbank restaurierten Backup: INSERT INTO Fahrradverleih.dbo.Products SELECT * FROM Fahrradverleih_Backup.dbo.Products WHERE CategoryId = 1 + $6 , 3 Schreiben Sie ein Backup in einer neuen oder anderen Installation des SQL Servers zurück, tauchen in der Liste der Backups der Datenbank natürlich keine passenden Einträge auf. In diesem Fall wählen Sie in die Wiederherstellen-Option VON MEDIEN und wählen Sie die Datei oder das Band aus, in der das Backup erfolgte. Abbildung 50: Restore einer Datenbank direkt aus einer Datei Wenn Sie eine Datenbank auf ein anderes System restaurieren (was ein ideales Vorgehen ist, um eine Datenbank von einem auf ein anderes System zu übertragen), müssen Sie u. U. den Speicherort der Datenbank anpassen. Der SQL Server verwendet ansonsten den originalen Administrieren des SQL Servers 112 Speicherort, der u. U. auf dem Zielsystem nicht vorhanden ist. Tragen Sie die gewünschten Dateinamen im Register OPTIONEN ein. Abbildung 51: Optionen -Register des Restore-Dialogs Wenn Sie eine vorhandene Datenbank mit dem Backup überschreiben wollen, müssen Sie in diesem Register die Option WIEDERHERSTELLUNG ÜBER VORHANDENE DATENBANK ERZWINGEN einstellen. D/ $- $ Der SQL Server Agent ermöglicht das automatische Ausführen bestimmter Aufgaben, wie z. B. dem Backup oder der Reorganisation einer Datenbank in bestimmten frei wählbaren Zeitabschnitten. So können Sie z. B. verschiedene Aufgaben wöchentlich (am Sonntag z. B.) ausführen und andere täglich (z. B. ab 0:00 Uhr). Außerdem kann der SQL Server Agent Systemressourcen überwachen und beim Über- bzw. Unterschreiten von festgelegten Werten Aktionen ausführen, wie zum Beispiel das Senden einer E-Mail. Jobs und Alarme können Sie von Hand über den SQL SERVER AGENT-Ordner im VERWALTUNG-Ordner des Enterprise Managers anlegen, was hier jedoch nicht beschrieben wird. Die häufigsten Jobs, wie das Backup einer Datenbank oder das regelmäßige Reorganisieren einer Datenbank, können sie wesentlich einfacher über einen Wartungsplan (Maintenance Plan) einrichten. Die Einrichtung dieser Pläne erreichen sie über das Kontextmenü der Datenbank (ALLE TASKS / WARTUNGSPLAN). Der Dialog zur Erstellung eines Wartungsplans führt Sie in mehreren Schritten durch die Erstellung von Jobs, mit denen Sie die Datenbank reorganisieren und sichern können. Ein Wartungsplan erzeugt die notwendigen Jobs für den SQL Server nahezu automatisch. Administrieren des SQL Servers 113 G 5## 5 , G ) $# 6 4 Der Wert einer Identity-Spalte wird ja, wie Sie bereits wissen, bei jedem neuen Datensatz vom SQL Server automatisch erhöht. Wenn Sie jedoch einen Datensatz einfügen wollen, und den Wert der Identity-Spalte selbst vergeben wollen (z. B. weil Sie den Datensatz an der Position eines zuvor gelöschten Datensatzes einfügen wollen), funktioniert dies zunächst einmal nicht. Sie können das automatische Einfügen der Identity-Spalte für eine Tabelle pro Benutzer jedoch auch abschalten und den Identity-Wert dann selbst definieren. Dazu müssen Sie den Datensatz mit TSQL-Anweisungen einfügen: /* Identity-Insert für Kunden-Tabelle ermöglichen */ SET IDENTITY_INSERT dbo.Kunden ON /* Datensatz mit eigenem Identity-Wert anfügen */ INSERT INTO Kunden (Kunden_Nr, Firmenname, Straße, Plz, Ort) VALUES (1001, 'Panzerknacker AG', 'Tresorweg 42', '12345', 'Entenhausen') /* Identity-Insert für Kunden-Tabelle wieder ausschalten */ SET IDENTITY_INSERT dbo.Kunden OFF Sie müssen dabei eine Feldliste angeben (INSERT INTO Kunden VALUES (...) funktioniert so nicht). Wenn Sie einen Datensatz hinten anfügen, verwendet der SQL Server beim nächsten neuen Datensatz den um 1 erhöhten Wert für die Identity-Spalte. Der Identity-Wert existierender Datensätze lässt sich leider nicht verändern. Wenn Sie einen solchen Datensatz neu definieren wollen, müssen Sie den Datensatz löschen und wie oben beschrieben wieder einfügen. G" 5 # 4 5 Temporär erzeugte Tabellen eignen sich für viele Aufgaben, bei denen normale Abfragen versagen. Oft ist es einfacher, eine Tabelle temporär zu erzeugen, weiter zu bearbeiten und den Inhalt auszugeben, als dazu teilweise kompliziert geschachtelte Abfragen zu verwenden. # 4 5 Temporäre Tabellen erzeugen Sie wie normale Tabellen. Dem Tabellennamen stellen Sie allerdings ein oder zwei # voraus: CREATE TABLE #MyTempTable (Year int NOT NULL, Amount real NOT NULL) Ein # bewirkt, dass die Tabelle nur für die aktuelle Sitzung gültig ist. Andere Sitzungen können nicht auf diese Tabelle zugreifen und zudem gleichzeitig gleichnamige Tabellen erzeugen. Wenn Sie zwei # angeben, ist die Tabelle für alle Sitzungen global. =, # 4 5 In einer Stored Procedure erzeugte temporäre Tabellen werden automatisch gelöscht, wenn die Stored Procedure beendet ist. Alle anderen lokalen Tabellen werden gelöscht, wenn die Sitzung beendet ist. Globale temporäre Tabellen werden automatisch erst dann gelöscht wenn der Server heruntergefahren wird (da beim Hochfahren die Datenbank tempdb, in der diese Tabellen gespeichert werden, neu erzeugt wird). Sie können eine temporäre Tabelle natürlich auch explizit löschen: DROP TABLE #MyTempTable Tipps und Tricks 114 7 # 4 5 > Normalerweise sollten Sie lokale temporäre Tabellen vor dem Erzeugen immer löschen (falls diese bereits in der aktuellen Sitzung erzeugt wurden). Da dabei allerdings ein Fehler auftritt wenn die Tabelle nicht existiert, sollten Sie zuvor abfragen, ob die Tabelle existiert. Dieses Abfragen kann auch vor dem Erzeugen oder Verwenden einer globalen temporären Tabelle sinnvoll sein. Zur Abfrage der Existenz einer lokalen temporären Tabelle verwenden Sie den folgenden »Trick«: DECLARE @TableName nvarchar(255) SET @TableName = 'tempdb.[' + SESSION_USER + '].#<Tabellenname>' if object_id(@TableName) is not null begin /* Tablle ist vorhanden und kann z. B. gelöscht werden */ DROP TABLE #<Tabellenname> end Bei der Abfrage der Objekt-Id der Tabelle müssen Sie den kompletten Tabellennamen angeben, der aus dem Datenbanknamen, dem Namen des Benutzers und dem eigentlichen Tabellennamen besteht. Damit Sie den aktuellen Benutzer korrekt mit in den Namen einbinden, ermitteln Sie dessen Namen über die Variable SESSION_USER. Da der Name auch Sonderzeichen beinhalten kann, sollten Sie diesen wie im Beispiel in eckige Klammern einfügen. Mit dem so zusammengesetzten Tabellennamen können Sie die Existenz der Tabelle ermitteln. Tipps und Tricks 115 , Bowman, Judith S., Emerson, Sandra L., Darnovsky Marcy: The practical SQL Handbook. Using Structured Query Language. Addison-Wesley Developers Press. 1997. Date, Chris J, Darwen Hugh: SQL-Der Standard. SQL/92 mit den Erweiterungen CLI und PSM. Addison Wesley München. 1999.Anmerkung: Standardwerk, aber kompliziert geschrieben und der Autor verweist sehr häufig für Erklärungen auf andere Kapitel. Soukup, Ron, Delaney, Kalen: Inside Microsoft SQL Server 7.0. Microsoft Press Redmond, Washington. 1999. Delaney, Kalen: Inside Microsoft SQL Server 2000. Microsoft Press Redmond, Washington. 2001. Anhang 116 " ) > ALTER-Anweisung 73, 86, 87, 94 Datenbankoptionen 31 Anweisungsrechte 62 Datenbank-Rollen 58 AppleTalk ADSP 15 Datenintegrität 17 Arbeitsspeicher 5 Datenseiten 22 Backup 106 Datentypen 38 Banyan VINES 15 bigint 38 BEGIN TRANSACTION 22 binary 39 Benutzerdefinierte Datentypen 18 bit 40 Benutzernamen 57 char 38 Benutzerverwaltung 57 cursor 40 Beziehungen 49 datetime 38 bigint-Datentyp 38 decimal 39 binary-Datentyp 39 float 39 bit-Datentyp 40 image 39 char-Datentyp 38 int 38 Check Constraints 45 money 39 Check-Einschränkungen 45 nchar 38 über SQL anlegen 54 ntext 39 Check-Option 72 numeric 39 Checkpoints 23 nvarchar 38 Client/Server-Konzept 17 real 39 Clustered Index 45 smalldatetime 38 COMMIT TRANSACTION 22 smallint 38 Constraints 18 smallmoney 39 Cursor 84 sql_variant 40 cursor-Datentyp 40 sysname 40 Database Owner 59, 68 table 40 Data-Mining 1 text 39 Data-Warehousing 2 timestamp 40 Dateigruppen 30 tinyint 38 Datenbankdiagramm 49 uniqueidentifier 40 Datenbanken varbinary 39 auf mehrere Dateien aufteilen 30 varchar 38 Dateigruppen 30 datetime-Datentyp 38 Default-Dateigruppe 30 DB-Benutzer 57 erzeugen 28 dbo 59, 68 im Zugriff beschränken 32 Debuggen 94 Optionen 31 im TSQL-Debugger 96 Primäre Dateigruppe 30 in Visual Studio .NET 99 RAID-Systeme 30 decimal-Datentyp 39 Transaktionsprotokoll 30 deleted 89 Wiederherstellungs-Modell 32 DENY 64 Index 117 Developer Edition 3 inserted 89 Diagramme 49 Installation 5 Dienst Manager 24 int-Datentyp 38 Dienste 5 IPC-Mechanismus 14 Diensteprogramme 15 Konsistenz 17 DRI 49 Kontrollstrukturen 81 Editionen Lazywriter-Thread 23 Developer 3 Log Sequenz Nummer 22 Enterprise 2 Login 57 MSDE 4 Login-Objekte 57 Personal 3 Logins Standard 2 anlegen 64 Windows CE 3 modifizieren 64 Einschränkungen 18 über SQL ändern 55 LSN 22 Maintenance Plan 113 Enterprise Edition 2 Microsoft Distributed Transaction Coordinator 19 Enterprise Manager 25 money-Datentyp 39 Festplatten 5 MSDE 4 Festplattenspeicher 5 MSDTC 19 File-Server 17 MSSQLServer-Dienst 19 float-Datentyp 39 Multi-Protocol 14 Fremdschlüssel Named Pipes 14 über SQL anlegen 55 nchar-Datentyp 38 Füllfaktor 44 Netzwerk-Bibliotheken 13 Funktionen 69, 86 NT-Authentifizierung 66 verändern 87 ntext-Datentyp 39 Gespeicherte Prozeduren 18, 73 numeric-Datentyp 39 Globale Variablen 80 nvarchar-Datentyp 38 GRANT 63 NWLink IPX/SPX 15 Gruppierte Indizes 45 Objektrechte 63 Guest 68 Objekt-Rechte 61 GUID-Werte 41 ODS 19 Haltepunkte OLAP 1 im TSQL-Debugger 98 Open Data Service 19 im Visual Studio .NET-Debugger 101 Operatoren 83 Hardware 5 Pages 22 Identitätsspalte 41 Personal Edition 3 IF-Abfrage 81 Primärschlüssel 40 image-Datentyp 39 Indizes 41 über SQL anlegen 54 Prozessor 5 Füllfaktor 44 Public-Rolle 59 Gruppierte Indizes 45 RAID-Systeme 6, 30 über SQL ändern 56 real-Datentyp 39 über SQL anlegen 55 Rechte Index 2 Datenbankspezifische Rechte 57 Parameter und Variablen 75 Systemweite Rechte 57 Rückgabetypen 75 Verwaltung 57 verändern 86 Recovering 23 sysname-Datentyp 40 Referentielle Integrität 49 Systemkatalog 23 mit DRI 49 Regeln 18 Tabellen Erzeugen 37 Rekursive Trigger 33 Temporäre 114 Restore 106 über SQL anlegen 53 REVOKE 64 table-Datentyp 40 ROLLBACK TRANSACTION 22 TCP/IP 13 Rollen 57, 58 TCP/IP-Sockets 14 anlegen 60 RowGUID 41 Temporäre Tabellen 114 text-Datentyp 39 Rules 18 timestamp-Datentyp 40 sa 68 tinyint-Datentyp 38 Seiten 22 Transaction Logs 21 Server Transaktionen 21 Registration im Enterprise Manager 25 Servername 5 Server-Rollen 58 Explizite 22 Implizite 21 Transaktionsprotokoll Service Manager 24 Größe 104 Sichten 18, 69, 70 verkleinern 105 Check-Option 72 Transaktionsprotokolle 21 Erweiterte Sicherheit 72 Trigger 18, 69, 88 sortieren 71 verändern 73 deleted-Tabelle 89 inserted-Tabelle 89 smalldatetime-Datentyp 38 Rollback 93 smallint-Datentyp 38 testen 92 smallmoney-Datentyp 39 verändern 94 Sortierung Default bei der Installation 13 SQL Server Agent 113 TSQL 81 Operatoren 83 TSQL-Debugger 96 SQL Server Dienste 5 Unique Constraint 43 SQL Server-Authentifizierung 57, 66 Unique Index 43 sql_variant-Datentyp 40 uniqueidentifier-Datentyp 40 SQLServerAgent-Dienst 19 varbinary-Datentyp 39 Standard Edition 2 varchar-Datentyp 38 Statistiken 33 Views 18, 69, 70 Stored Procedure 69 Visual Studio .NET Stored Procedures 18, 73 zum Debuggen von TSQL 99 Aufruf in VBA 77 Wartungsplan 113 Globale Variablen 80 While-Schleife 81 Output-Parameter 77 Wiederherstellungs-Modelle 32, 107 Index 3 Windows CE Edition 3 Windows-Authentifizierung 57 Windows NT-Authentifizierung 66 Zerrissene Seiten 33 Index 4