T-SQL UPDATE – JOIN, CTE & Performance – Beispiele & Best Practices

📝 T-SQL UPDATE · JOIN, CTE & Performance

Datenmodifikation mit JOINs · CTE · MERGE · Best Practices
UPDATE-Anweisungen mit Joins, CTEs und Unterabfragen – Daten aus anderen Tabellen effizient aktualisieren (SQL Server / Azure SQL).
⚠️ Achtung bei UPDATE ohne WHERE! Eine UPDATE-Anweisung ohne einschränkende WHERE-Klausel oder passenden JOIN aktualisiert ausnahmslos alle Zeilen der Tabelle. Verwenden Sie solche Anweisungen daher stets mit Bedacht.

1. Einfaches UPDATE – Grundform

BASIS
📌 Wofür? Aktualisieren von Werten in einer Tabelle, entweder für alle Zeilen oder gefiltert mit WHERE.
-- Einfache Aktualisierung einer Spalte mit Bedingung 
UPDATE Mitarbeiter 
SET Gehalt = Gehalt * 1.05 
WHERE AbteilungID = 5; 
 
-- Mehrere Spalten auf einmal aktualisieren 
UPDATE Produkte 
SET Preis = ROUND(Preis * 1.1, 2), 
LetzteAktualisierung = GETDATE() 
WHERE KategorieID IN (2, 5);
💡 Erklärung: Die Syntax ist intuitiv: UPDATE legt die Tabelle fest, SET definiert die neuen Werte. Ein WHERE-Filter ist optional – ohne ihn werden tatsächlich alle Zeilen überschrieben.

2. UPDATE mit JOIN – Daten aus anderer Tabelle

JOIN / FROM
📌 Wofür? Eine Tabelle mit Werten aus einer anderen Tabelle aktualisieren, basierend auf einer Verknüpfungsbedingung. Die FROM-Klausel definiert die Quelle, der JOIN die Beziehung.
-- Beispiel: Preise aus einer Preistabelle aktualisieren 
UPDATE P 
SET P.Preis = U.NeuPreis 
FROM Produkte P 
INNER JOIN PreisUpdate U ON P.Code = U.Code; 
 
-- Alternative mit WHERE (impliziter JOIN) – aber weniger lesbar 
UPDATE alt 
SET alt.Name = neu.Name 
FROM Person_Archiv alt, Person_Neu neu 
WHERE alt.Id = neu.Id; 
 
-- Wichtig: Aliase machen die Zieltabelle eindeutig
🔗 Erklärung: Die FROM-Klausel definiert, welche weiteren Tabellen in die Aktualisierung einbezogen werden. Der JOIN legt fest, wie die Tabellen verknüpft werden. Wichtig: Sie müssen die zu aktualisierende Tabelle im UPDATE sowie erneut in der FROM-Klausel mit einem eindeutigen Alias referenzieren.
🚀 Performance-Tipp: Für große Datenmengen sollten Sie auf den verknüpften Spalten (z. B. Product.Code und PriceUpdate.Code) einen Index erstellen – das beschleunigt den Abgleich enorm.

3. UPDATE mit CTE – sauber & aggregiert

COMMON TABLE EXPRESSION
📌 Wofür? In einer CTE können Sie komplexe Berechnungen oder Aggregationen durchführen, bevor Sie die darin enthaltenen Daten gezielt aktualisieren.
-- Beispiel: Status in Customers aktualisieren basierend auf Gesamtguthaben der BankAccounts 
WITH CustomerBalances AS ( 
SELECT C.CustomerID, SUM(BA.Balance) AS TotalBalance 
FROM Customers C 
INNER JOIN BankAccounts BA ON C.CustomerID = BA.CustomerID 
GROUP BY C.CustomerID 
) 
UPDATE C 
SET C.Status = CASE  
 WHEN CB.TotalBalance >= 3000 THEN 'Rich' 
 ELSE 'Poor' 
 END 
FROM Customers C 
INNER JOIN CustomerBalances CB ON C.CustomerID = CB.CustomerID; 
 
-- Wichtig: Die CTE muss eindeutige Zeilen referenzieren, z. B. via PRIMARY KEY
🧩 Erklärung: Common Table Expressions (CTEs) verbessern die Lesbarkeit komplexer Updates enorm. Im Beispiel wird zuerst die Gesamtsumme pro Kunde berechnet, danach wird der Status in der Tabelle Customers aktualisiert. Die CTE kann selbst direkt das Ziel des Updates sein, sofern sie keine Aggregationen oder komplexen Joins enthält.
💡 Wissenswert: Eine CTE verhält sich wie eine Sicht (View). Wenn Sie eine CTE aktualisieren, wird direkt die zugrunde liegende Basistabelle geändert.

4. MERGE – INSERT + UPDATE kombiniert (UPSERT)

MERGE
📌 Wofür? Mit MERGE können Sie in einer einzigen Anweisung Einfügen (INSERT), Aktualisieren (UPDATE) und Löschen (DELETE) auf Basis eines Quell-Datasets kombinieren. Besonders nützlich für die Synchronisation zweier Tabellen.
-- Preisliste mit MERGE verarbeiten (einfügen oder aktualisieren) 
MERGE INTO Produkte AS Ziel 
USING PreisUpdate AS Quelle 
ON Ziel.Code = Quelle.Code 
WHEN MATCHED THEN  
UPDATE SET Ziel.Preis = Quelle.NeuPreis, 
Ziel.LetzteAktualisierung = GETDATE() 
WHEN NOT MATCHED THEN 
INSERT (Code, Name, Preis, LetzteAktualisierung) 
VALUES (Quelle.Code, Quelle.Name, Quelle.NeuPreis, GETDATE()); 
 
-- Quelle kann eine Tabelle, CTE, oder VALUES-Konstrukt sein
🔄 Erklärung: Die MERGE-Anweisung vergleicht Ziel- und Quelltabelle anhand einer Bedingung (ON). Je nachdem, ob ein Datensatz bereits existiert oder nicht, wird entweder aktualisiert (WHEN MATCHED) oder neu eingefügt (WHEN NOT MATCHED). Das spart mehrere Einzelabfragen und reduziert den Code.

5. Mehrere Tabellen in UPDATE mit JOIN

MEHRERE TABELLEN
📌 Wofür? Zwei oder mehr Quelltabellen können ebenfalls in einem UPDATE genutzt werden – besonders nützlich, wenn Daten aus mehreren Quellen aggregiert werden müssen.
-- Tabelle1 aus Tabelle2 und Tabelle3 aktualisieren 
UPDATE t1 
SET t1.SpalteA = t2.SpalteX, 
t1.SpalteB = t3.SpalteY 
FROM Tabelle1 t1 
INNER JOIN Tabelle2 t2 ON t1.Id = t2.FremdId 
INNER JOIN Tabelle3 t3 ON t1.Id = t3.FremdId 
WHERE t1.Status = 'aktiv'; 
 
-- Praktisch: Kombinierte Daten aus Lookup-Tabellen 
UPDATE Auftraege 
SET Auftraege.KundenName = k.Name, 
Auftraege.ProduktBezeichnung = p.Bezeichnung 
FROM Auftraege a 
INNER JOIN Kunden k ON a.KundenId = k.Id 
INNER JOIN Produkte p ON a.ProduktId = p.Id;
Erklärung: Durch mehrere Joins in der FROM-Klausel ist es möglich, eine Tabelle mit Werten aus zwei oder mehreren Quellen zu aktualisieren. Der SQL Server-Optimizer löst die Joins intern auf – für ihn ist es eine natürliche Erweiterung des einfachen JOIN-Updates.

6. Performance-Tipps & Best Practices

OPTIMIERUNG
-- 1. Index auf JOIN-Spalten: Beschleunigt den Abgleich enorm 
CREATE INDEX IX_Produkte_Code ON Produkte(Code); 
 
-- 2. Begrenzung der zu aktualisierenden Zeilen (z. B. mit TOP) 
UPDATE TOP (1000) LogEintraege 
SET Status = 'processed' 
WHERE Verarbeitet = 0; 
 
-- 3. OUTPUT-Klausel für Kontrolle oder Auditing 
UPDATE Mitarbeiter 
SET Gehalt = Gehalt * 1.05 
OUTPUT deleted.Gehalt AS AlterWert, 
inserted.Gehalt AS NeuerWert, 
inserted.MitarbeiterID 
WHERE AbteilungID = 3; 
 
-- 4. Transaktion für konsistente, mehrstufige Änderungen 
BEGIN TRANSACTION; 
UPDATE Bestand SET Menge = Menge - 10 WHERE ProduktID = 4711; 
UPDATE Auftraege SET Status = 'versendet'; 
COMMIT; -- bei Fehler: ROLLBACK
📈 Wichtige Tipps:
  • Indizes nutzen: Stellen Sie sicher, dass die in der JOIN-ON-Klausel verwendeten Spalten indiziert sind. Das verbessert die Performance massiv.
  • Große Updates in Batches: Für sehr viele Zeilen ist ein TOP (n) in einer Schleife oft die bessere Wahl, um lange Sperren zu vermeiden.
  • Transaktionen: Bei mehreren zusammenhängenden Updates verwenden Sie BEGIN TRAN + COMMIT, um Konsistenz sicherzustellen.
  • OUTPUT-Klausel: Mit OUTPUT können Sie vorherige und neue Werte abfragen – ideal für Logging oder Debugging.

📌 Wann verwende ich welche Methode?

/* Einfaches UPDATE */ → Änderung in einer Tabelle, kleiner Filter. 
/* UPDATE mit JOIN */ → Werte aus einer anderen Tabelle übernehmen (z. B. Preis- oder Stammdaten). 
/* UPDATE mit CTE */ → Komplexe Vorberechnung oder Aggregation, bevor aktualisiert wird. 
/* MERGE (UPSERT) */ → Synchronisation zweier Tabellen (einfügen + aktualisieren in einem Schritt). 
/* Mehrere Tabellen im JOIN */ → Aktualisierung aus zwei oder mehr Quelltabellen gleichzeitig. 

⚠️ Besondere Vorsicht

  • Ein UPDATE ohne WHERE oder passenden JOIN betrifft wirklich alle Zeilen.
  • Bei der Verwendung von UPDATE mit JOIN kann es – wenn die JOIN-Bedingung mehrere Zeilen in der Quelltabelle trifft – zu nicht-deterministischen Ergebnissen kommen. SQL Server wählt dann willkürlich einen der möglichen Werte aus.
  • Testen Sie Updates in einer Entwicklungsumgebung und überprüfen Sie die Änderungen vorab mit einer SELECT-Abfrage, die exakt den gleichen JOIN verwendet.

Fazit: Mit UPDATE...FROM und UPDATE...WITH (CTE) lassen sich selbst komplexe Tabellenaktualisierungen in SQL Server elegant, lesbar und performant umsetzen. Gut gewählte Indizes, Batch-Verarbeitung und die OUTPUT-Klausel runden das Repertoire für den produktiven Einsatz ab.