Сканирование одной таблицы, отсутствие оконной функции, одиночная группировка, нет проблем с дублирующимися датами, одинаковая производительность с оконными функциями или даже они превосходят их при действительно больших запросах. (Обновление: я не знаю, как он работает по сравнению с методом TOP 1 WITH TIES / CROSS APPLY. Так как он использует сканирование, он может быть медленнее в некоторых ситуациях.)
SELECT
LogEntryID = Convert(int, Substring(Packed, 9, 4)),
FileID = Convert(int, Substring(Packed, 13, 4)),
CreatedOn = Convert(datetime, Substring(Packed, 1, 8)),
EventTypeID = Convert(int, Substring(Packed, 17, 4))
FROM
(
SELECT
Packed = Max(
Convert(binary(8), CreatedOn)
+ Convert(binary(4), LogEntryID)
+ Convert(binary(4), FileID)
+ Convert(binary(4), EventTypeID)
)
FROM LogEntries
WHERE EventTypeID IN (2,4)
GROUP BY ClientName
) X
Если кто-то хотел бы увидеть это в действии, вот сценарий создания:
USE tempdb
CREATE TABLE LogEntries (
LogEntryID int not null identity(1,1),
FileID int,
CreatedOn datetime,
EventTypeID int,
ClientName varchar(30)
)
INSERT LogEntries VALUES (1, GetDate()-20, 2, 'bob')
INSERT LogEntries VALUES (1, GetDate()-19, 3, 'bob')
INSERT LogEntries VALUES (1, GetDate()-18, 4, 'bob')
INSERT LogEntries VALUES (1, GetDate()-17, 3, 'bob')
INSERT LogEntries VALUES (1, GetDate()-19.5, 2, 'anna')
INSERT LogEntries VALUES (1, GetDate()-18.5, 3, 'anna')
INSERT LogEntries VALUES (1, GetDate()-17.5, 4, 'anna')
INSERT LogEntries VALUES (1, GetDate()-16.5, 3, 'anna')
Обратите внимание, что этот метод использует внутреннее представление байтов данных типов данных, имеющих тот же порядок, что и значения типа. Упакованные типы данных, такие как float или decimal, НЕ будут работать: для этого потребуется сначала преобразовать их во что-нибудь подходящее, например, int, bigint или символьные.
Кроме того, новые типы данных Date и Time в SQL 2008 имеют разные представления, которые не будут правильно упаковываться для использования с этим методом. Я еще не исследовал тип данных Time, но для типа данных Date:
DECLARE @d date
SET @d ='99990101'
SELECT Convert(binary(3), @d) -- 0x6EB837
Фактическое значение - 0x37B86E, поэтому оно хранится в обратном байтовом порядке (нулевая дата - 0001-01-01).