⚡ 7 SQL-Tricks für MS SQL Server
inspiriert von Lukas Eders berühmter Vortragsreihe, umgesetzt für Microsoft T-SQL.
Alles ist eine Tabelle, rekursive CTEs, Fensterfunktionen, Lückenanalyse und mehr – diese sieben Techniken zeigen, wie weit man mit reinem deklarativem SQL gehen kann. Fokus liegt auf MS SQL Server 2017+ (kompatibel mit neueren Versionen). Keine imperative Schleifenlogik, dafür elegante, lesbare Abfragen.
-- Werte als Tabelle erzeugen (MS SQL Server)
SELECT *
FROM (VALUES (1), (2), (3)) AS t(a);
-- INSERT als "INSERT ... SELECT ..." (Tabellen einfügen)
CREATE TABLE #temp (zahl INT);
INSERT INTO #temp (zahl)
SELECT v.a
FROM (VALUES (10),(20),(30)) v(a);
SELECT * FROM #temp;
DROP TABLE #temp;
-- Zahlen von 1 bis 10 rekursiv erzeugen (MS SQL Server)
WITH Rekursion AS (
SELECT 1 AS Zahl -- Anker / Seed
UNION ALL
SELECT Zahl + 1
FROM Rekursion
WHERE Zahl < 10
)
SELECT * FROM Rekursion
OPTION (MAXRECURSION 100);
-- Laufende Summe (running total) pro Abteilung
SELECT
Abteilung,
Mitarbeiter,
Gehalt,
SUM(Gehalt) OVER (PARTITION BY Abteilung ORDER BY Mitarbeiter
ROWS UNBOUNDED PRECEDING) AS Laufende_Summe
FROM Angestellte;
-- Beispiel: Login-Daten eines Users – längste Serie von aufeinanderfolgenden Tagen
WITH LoginDaten AS (
SELECT DISTINCT CAST(LoginZeit AS DATE) AS LoginDatum
FROM BenutzerLogins
WHERE BenutzerID = 123
),
Gruppiert AS (
SELECT LoginDatum,
ROW_NUMBER() OVER (ORDER BY LoginDatum) AS rn
FROM LoginDaten
),
Gruppen AS (
SELECT LoginDatum,
DATEADD(day, -rn, LoginDatum) AS Gruppe
FROM Gruppiert
)
SELECT
MIN(LoginDatum) AS Start,
MAX(LoginDatum) AS Ende,
COUNT(*) AS Tage
FROM Gruppen
GROUP BY Gruppe
ORDER BY Tage DESC;
-- Gruppieren von aufeinanderfolgenden Zeilen mit gleichem Vorzeichen (positive/negative Beträge)
WITH DatenMitRN AS (
SELECT ID, Betrag,
SIGN(Betrag) AS Vorzeichen,
ROW_NUMBER() OVER (ORDER BY ID) AS rn
FROM Transaktionen
),
Grenzen AS (
SELECT *,
CASE WHEN LAG(Vorzeichen) OVER (ORDER BY ID) != Vorzeichen
THEN rn END AS StartBlock,
CASE WHEN LEAD(Vorzeichen) OVER (ORDER BY ID) != Vorzeichen
THEN rn END AS EndBlock
FROM DatenMitRN
),
Bloecke AS (
SELECT ID, Betrag, Vorzeichen,
MAX(StartBlock) OVER (ORDER BY ID ROWS UNBOUNDED PRECEDING) AS BlockStart,
MIN(EndBlock) OVER (ORDER BY ID ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS BlockEnd
FROM Grenzen
)
SELECT *, (BlockEnd - BlockStart + 1) AS BlockLaenge
FROM Bloecke;
-- Finde alle möglichen Summen aus einer Liste von Zahlen (2^n Kombinationen)
WITH Items AS (
SELECT 1 AS ID, 7120 AS Wert UNION ALL
SELECT 2, 8150 UNION ALL SELECT 3, 8255 UNION ALL SELECT 4, 9051
),
RekSum AS (
SELECT Wert, CAST(Wert AS VARCHAR(MAX)) AS Pfad, ID
FROM Items
UNION ALL
SELECT r.Wert + i.Wert, r.Pfad + ' + ' + CAST(i.Wert AS VARCHAR), i.ID
FROM RekSum r
JOIN Items i ON r.ID < i.ID
)
SELECT Wert, Pfad
FROM RekSum
ORDER BY Wert;
-- T-SQL Simulation eines "Running Total with Floor" mittels Fensterfunktion & Korrektur
WITH Trans AS (
SELECT Datum, Betrag,
SUM(Betrag) OVER (ORDER BY Datum ROWS UNBOUNDED PRECEDING) AS StandardTotal
FROM KontoBewegungen
)
SELECT Datum, Betrag,
CASE
WHEN StandardTotal < 0 THEN 0
ELSE StandardTotal
END AS TotalGekappt
FROM Trans;
-- Bessere Variante für echten "Floor(0)" rekursiv (tatsächliches Abschneiden)
-- (Hier als rekursiver CTE mit IIF LIMIT 0)
WITH Bestand AS (
SELECT Datum, Betrag,
IIF(Betrag < 0, 0, Betrag) AS BestandNeu,
1 AS Reihenfolge
FROM KontoBewegungen
WHERE Reihenfolge = 1
UNION ALL
SELECT b2.Datum, b2.Betrag,
IIF(b.BestandNeu + b2.Betrag < 0, 0, b.BestandNeu + b2.Betrag),
b.Reihenfolge + 1
FROM Bestand b
JOIN KontoBewegungen b2 ON b2.Reihenfolge = b.Reihenfolge + 1
)
SELECT * FROM Bestand
OPTION (MAXRECURSION 0);