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.