T-SQL Grundkurs
Die wichtigsten Konzepte kompakt: SELECT, WHERE, JOINs, Gruppierung, Unterabfragen, DML und Indizes – alles auf einer Seite
📌 Worum geht es in diesem Grundkurs?
Dieser dreiteilige Grundkurs vermittelt Ihnen die wesentlichen Fähigkeiten, um mit T-SQL (Transact-SQL) auf Microsoft SQL Server zu arbeiten. Sie lernen, Daten abzufragen, zu filtern, zu verknüpfen, zu aggregieren, zu ändern und zu löschen. Zudem erhalten Sie einen Einblick in die Indexoptimierung für bessere Performance. Die Beispiele basieren auf einer einfachen Demo-Datenbank mit den Tabellen
Kunden, Bestellungen und Produkte.
🎯 Ziel: Nach der Lektüre können Sie eigenständig SQL-Abfragen schreiben, Daten analysieren und einfache Wartungsaufgaben durchführen.
📖 Teil 1: Einfache Abfragen – SELECT, FROM, WHERE, ORDER BY
SELECT ist das Herzstück jeder Datenabfrage. Mit
FROM legen Sie die Tabelle fest, WHERE filtert Zeilen, ORDER BY sortiert das Ergebnis.
-- Alle Spalten aus der Kundentabelle abrufen SELECT * FROM dbo.Kunden; -- Nur bestimmte Spalten, mit Filter und Sortierung SELECT Nachname, Vorname, Ort FROM dbo.Kunden WHERE Ort = 'Berlin' ORDER BY Nachname ASC; -- Verwendung von Aliasen (AS) SELECT Nachname AS Name, Ort AS Stadt FROM dbo.Kunden;
Wichtige Operatoren in WHERE:
=,>,<,>=,<=,<>(ungleich)LIKEmit Wildcards (%für beliebig viele Zeichen,_für ein Zeichen)INfür eine WertelisteBETWEENfür WertebereicheAND,OR,NOTfür Verknüpfungen
-- Komplexe Filter SELECT * FROM dbo.Bestellungen WHERE Bestelldatum BETWEEN '2025-01-01' AND '2025-03-31' AND Gesamtwert > 100 AND Status IN ('Versendet', 'Bezahlt');
💡 Best Practice: Vermeiden Sie
SELECT * in Produktivumgebungen – listen Sie immer nur die benötigten Spalten auf. Das spart Netzwerkverkehr und beschleunigt die Abfrage.
🔗 Teil 2: JOINs, GROUP BY und Aggregatsfunktionen
JOINs verbinden mehrere Tabellen über Schlüsselspalten. Die wichtigsten Typen:
INNER JOIN– nur übereinstimmende Zeilen aus beiden TabellenLEFT JOIN– alle Zeilen der linken Tabelle, auch ohne Treffer in der rechtenRIGHT JOIN– analog, aber seltenerFULL OUTER JOIN– alle Zeilen aus beiden Seiten
-- INNER JOIN: Kunden und ihre Bestellungen SELECT K.Nachname, B.Bestellnummer, B.Bestelldatum FROM dbo.Kunden K INNER JOIN dbo.Bestellungen B ON K.KundenID = B.KundenID; -- LEFT JOIN: Kunden auch ohne Bestellungen (z. B. für Analyse) SELECT K.Nachname, COUNT(B.Bestellnummer) AS AnzahlBestellungen FROM dbo.Kunden K LEFT JOIN dbo.Bestellungen B ON K.KundenID = B.KundenID GROUP BY K.Nachname ORDER BY AnzahlBestellungen DESC;
Aggregatsfunktionen wie
COUNT, SUM, AVG, MIN, MAX fassen viele Zeilen zu einem Wert zusammen. In Kombination mit GROUP BY erhalten Sie Zwischensummen pro Kategorie. Die HAVING-Klausel filtert nach der Aggregation (ähnlich wie WHERE, aber für Gruppen).
-- Gesamtumsatz pro Kunde (nur Kunden mit Umsatz über 5000 €) SELECT K.KundenID, K.Nachname, SUM(B.Gesamtwert) AS Gesamtumsatz FROM dbo.Kunden K INNER JOIN dbo.Bestellungen B ON K.KundenID = B.KundenID GROUP BY K.KundenID, K.Nachname HAVING SUM(B.Gesamtwert) > 5000 ORDER BY Gesamtumsatz DESC;
📌 Achtung: Spalten in der
SELECT-Liste, die nicht aggregiert werden, müssen in der GROUP BY-Klausel erscheinen. Sonst erhalten Sie einen Fehler (außer in einigen speziellen Datenbankmodi).
📦 Unterabfragen und abgeleitete Tabellen
Unterabfragen (Subqueries) sind SELECT-Anweisungen in Klammern, die innerhalb einer äußeren Abfrage verwendet werden. Sie können in
WHERE, SELECT, FROM oder HAVING auftreten. Man unterscheidet zwischen:
- Skalare Unterabfragen – liefern genau einen Wert (eine Zeile, eine Spalte).
- Mehrwertige Unterabfragen – liefern eine Spalte mit mehreren Werten (z. B. mit
IN). - Korrelierte Unterabfragen – beziehen sich auf die äußere Abfrage (werden für jede Zeile neu ausgeführt).
-- Skalare Unterabfrage: Kunden mit Bestellungen über dem Durchschnitt SELECT Nachname, Vorname FROM dbo.Kunden WHERE KundenID IN ( SELECT KundenID FROM dbo.Bestellungen GROUP BY KundenID HAVING AVG(Gesamtwert) > ( SELECT AVG(Gesamtwert) FROM dbo.Bestellungen ) ); -- Abgeleitete Tabelle (Subquery in FROM) SELECT sub.Jahr, COUNT(*) AS Anzahl FROM ( SELECT YEAR(Bestelldatum) AS Jahr FROM dbo.Bestellungen ) sub GROUP BY sub.Jahr;
💡 Tipp: Korrelierte Unterabfragen können langsam sein. Oft lassen sie sich durch einen JOIN oder einen Fensterausdruck (
ROW_NUMBER() etc.) ersetzen.
✏️ Teil 3: Daten ändern – INSERT, UPDATE, DELETE
DML steht für Data Manipulation Language. Mit diesen Befehlen verändern Sie die Daten in Ihren Tabellen.
-- INSERT: Neue Zeilen hinzufügen INSERT INTO dbo.Kunden (Nachname, Vorname, Ort) VALUES (N'Müller', N'Anna', N'Hamburg'); -- INSERT mit SELECT (z. B. Daten kopieren) INSERT INTO dbo.Kunden_Archiv SELECT * FROM dbo.Kunden WHERE LetzteBestellung < '2023-01-01'; -- UPDATE: Daten ändern (mit WHERE, sonst alle Zeilen!) UPDATE dbo.Bestellungen SET Status = 'Storniert' WHERE Bestelldatum < '2024-01-01' AND Status = 'Offen'; -- DELETE: Zeilen löschen (auch hier Vorsicht mit WHERE) DELETE FROM dbo.TempBestellungen WHERE Bestelldatum < DATEADD(YEAR, -2, GETDATE());
🚨 Warnung: Ein
UPDATE oder DELETE ohne WHERE betrifft alle Zeilen der Tabelle. Stellen Sie sicher, dass Sie vor der Ausführung eine Sicherung haben oder in einer Transaktion arbeiten (BEGIN TRAN / ROLLBACK).
📈 Indizes – Das Fundament für schnelle Abfragen
Indizes sind Hilfsstrukturen, die SQL Server nutzt, um Daten schnell zu finden. Ein Clustered Index (nur einer pro Tabelle) bestimmt die physische Sortierung der Daten. Non‑Clustered Indizes sind separate B‑Bäume, die auf die Datenzeilen verweisen.
-- Clustered Index auf Primärschlüssel (oft automatisch) CREATE CLUSTERED INDEX idx_Kunden_KundenID ON dbo.Kunden (KundenID); -- Non‑Clustered Index für häufige Suchkriterien CREATE NONCLUSTERED INDEX idx_Kunden_Ort ON dbo.Kunden (Ort) INCLUDE (Nachname, Vorname); -- Eindeutigen Index erzwingen (verhindert Duplikate) CREATE UNIQUE INDEX idx_Unique_Email ON dbo.Kunden (Email);
Wann brauche ich welchen Index?
- Clustered Index auf Spalten mit vielen Bereichszugriffen (z. B.
BETWEEN,ORDER BY). - Non‑Clustered Index für Spalten in
WHERE-,JOIN- oderORDER BY-Klauseln. INCLUDEfügt zusätzliche Spalten auf Blattebene hinzu, um Key‑Lookups zu vermeiden (Covering Index).- Zu viele Indizes verlangsamen
INSERT,UPDATE,DELETE. Finden Sie die Balance.
💡 Best Practice: Überprüfen Sie regelmäßig fehlende Indizes mit DMVs oder dem Ausführungsplan. Verwenden Sie den Database Tuning Advisor für Empfehlungen.
🔧 Nützliche T-SQL-Funktionen
String-Funktionen:
LEN(@string)– Länge eines StringsCHARINDEX('M', @string)– Position eines TeilstringsSUBSTRING(@string, start, length)– Teilstring extrahierenUPPER(@string),LOWER(@string)– Groß-/KleinschreibungREPLACE(@string, 'alt', 'neu')– Zeichen ersetzen
GETDATE()– aktuelles Datum und Uhrzeit (Server-Zeit)DATEADD(day, 7, GETDATE())– Datum addierenDATEDIFF(day, Start, Ende)– Differenz zwischen zwei DatenYEAR(Spalte),MONTH(...),DAY(...)– Teile extrahierenFORMAT(GETDATE(), 'yyyy-MM-dd')– Datum formatieren (verbraucht viele Ressourcen)
CAST(Spalte AS INT)– TypumwandlungCONVERT(INT, Spalte)– mit Formatierungsoptionen
✅ Checkliste: So schreiben Sie guten T-SQL-Code
- Immer WHERE-Klausel prüfen – besonders vor UPDATE/DELETE
- JOINs explizit schreiben – vermeiden Sie implizite Joins (Komma-Syntax)
- Aliase verwenden – Tabellen mit sinnvollen Kürzeln versehen (z. B. K, B, P)
- Niemals SELECT * in Produktion – Spalten explizit aufführen
- Indizes und Statistiken aktuell halten – regelmäßige Wartung einplanen
- Transaktionen kurz halten – BEGIN TRAN ... COMMIT nicht unnötig ausdehnen
- Ausführungspläne verstehen – bei langsamen Abfragen immer den Plan prüfen
- SQL Injection vermeiden – Parameter verwenden, keine zusammengesetzten Strings
📌 Weiterführende Themen: Nach diesem Grundkurs können Sie sich mit Fensterfunktionen (
ROW_NUMBER(), LAG()), Common Table Expressions (CTEs), dynamischen Abfragen, gespeicherten Prozeduren und Fehlerbehandlung (TRY...CATCH) beschäftigen. Viel Erfolg auf Ihrem Weg zum T-SQL-Profi!