By Frank Kalis
Zugegeben ist das Subjekt nicht sehr treffend, aber im Moment fällt mir kein Besseres ein.
Gestern stellte jemand auf SQL Server Central.com die Frage, wie man zu jedem Namen mehr als ein Datum anzeigen kann. Genauer gesagt, die beiden aktuellsten Daten. Diese Frage kann man leicht auf die Northwind Beispieldatenbank übertragen: Zeige mir zu jedem Kunden die beiden letzten Bestelldaten ein.
Ein Weg, dies zu erreichen, ist folgender:
SELECT t1.CustomerID, t1.OrderDate FROM Orders t1 WHERE t1.OrderDate IN (SELECT TOP 2 t2.OrderDate FROM Orders t2 WHERE t2.CustomerID = t1.CustomerID ORDER BY t2.OrderDate DESC) ORDER BY t1.CustomerID, t1.OrderDate DESC CustomerID OrderDate ---------- ------------------------------------------------------ ALFKI 1998-04-09 00:00:00.000 ALFKI 1998-03-16 00:00:00.000 ANATR 1998-03-04 00:00:00.000 ANATR 1997-11-28 00:00:00.000 ...
Sollte der Kunde mehr als einmal an einem dieser beiden Tage geordert haben, wird dies - auch ohne Angabe von "with ties" - berücksichtigt:
... SAVEA 1998-05-01 00:00:00.000 SAVEA 1998-04-17 00:00:00.000 SAVEA 1998-04-17 00:00:00.000 ...
Eine weitere Alternative bietet folgendes Statement:
SELECT t1.CustomerID , t1.OrderDate FROM Orders t1 WHERE (SELECT COUNT(*) FROM Orders WHERE OrderDate<=t1.OrderDate AND CustomerID = t1.CustomerID) <=2 ORDER BY t1.CustomerID, t1.OrderDate DESC
Zumindest in der Northwind Datenbank zeigt sich ein interessanter Unterschied wenn man den Output von SET STATISTICS IO betrachtet:
Table 'Orders'. Scan count 827, logical reads 269412, physical reads 0, read-ahead reads 0.
für das erste Statement und
Table 'Worktable'. Scan count 823, logical reads 3351, physical reads 0, read-ahead reads 0. Table 'Orders'. Scan count 2, logical reads 44, physical reads 0, read-ahead reads 0.
für das zweite. Auch die Ausführungszeiten sprechen für sich
------------------------------------------------------ 1900-01-01 00:00:01.243 (1 row(s) affected)
für Alternative 1, sowie
------------------------------------------------------ 1900-01-01 00:00:00.080 (1 row(s) affected)
für Alternative 2. Also, zumindest in der Northwind Datenbank performt das zweite Statement deutlich besser als das erste.
Ein weiterer Unterschied zwischen beiden Statements soll nicht unerwähnt bleiben. Während das erste Statement "automatisch" Ties handhabt, und damit u.U. mehr als 2 Datensätze pro Gruppe wiedergibt, gibt das zweite Statement stets nur die "ersten beiden" Datensätze wieder, egal, wieviele weitere ebenfalls in die Gruppe passen würden.