Механически есть несколько способов сделать это.Вы можете использовать временные таблицы / переменную таблицы.Другой способ - с вложенными запросами и / или CTE, как показало @Aaron_Bertrand.Третий способ - использовать WINDOWED FUNCTIONS, такие как ...
SELECT CarName,
COUNT(*) as theCount,
MAX(Count(*)) OVER(PARTITION BY 'foo') as MaxPerGroup
FROM dbo.tbl_Cars
GROUP BY CarName
A DISFAVORED (readricric). Четвертым способом является использование ключевого слова COMPUTE как такового ...
SELECT CarID, CarName, Count(*)
FROM dbo.tbl_Cars
GROUP BY CarID, CarName
COMPUTE MAX(Count(*))
Ключевое слово COMPUTE
генерирует итоги, которые отображаются в виде дополнительных сводных столбцов в конце набора результатов ( см. ).В приведенном выше запросе вы на самом деле увидите два набора записей.
Самый быстрый
Теперь следующая проблема - «лучший / самый быстрый / самый простой».Я сразу думаю о indexed view
.Как мягко напомнил мне @Aaron, индексированные представления имеют всевозможные ограничения.Однако вышеприведенная стратегия позволяет вам создать индексированное представление для SELECT ... FROM..GROUP BY.Затем, выбрав в индексированном представлении, примените предложение WINDOWED FUNCTION.
Однако, не зная больше о вашем дизайне, любому будет сложно сказать, что лучше.Вы получите освещение быстрых запросов из индексированного представления.Эта производительность имеет свою цену, хотя.Цена это расходы на техническое обслуживание.Если базовая таблица является целью большого количества операций вставки / обновления / удаления, обслуживание индексированного представления снизит производительность в других областях.
Если вы немного больше расскажете о вашем сценарии использования и шаблонах доступа к данным, люди смогут поделиться с вами большей проницательностью.
MICRO PERFORMANCE TEST
Итак, я сгенерировал небольшой скрипт данных и посмотрел на номера профайлера sql для производительности CTE по сравнению с оконными функциями.Это микротест, поэтому попробуйте некоторые действительные числа в вашей системе при реальной нагрузке .
Генерация данных:
Create table Cars ( CarID int identity (1,1) primary key,
CarName varchar(20),
value int)
GO
insert into Cars (CarName, value)
values ('Buick', 100),
('Ford', 10),
('Buick', 300),
('Buick', 100),
('Pontiac', 300),
('Bmw', 100),
('Mecedes', 300),
('Chevy', 300),
('Buick', 100),
('Ford', 200);
GO 1000
ЭтоСкрипт генерирует 10000 строк.Затем я запускал каждый из четырех следующих запросов несколько раз:
--just group by
select CarName,COUNT(*) countThis
FROM Cars
GROUP BY CarName
--group by with compute (BAD BAD DEVELOPER!)
select CarName,COUNT(*) countThis
FROM Cars
GROUP BY CarName
COMPUTE MAX(Count(*));
-- windowed aggregates...
SELECT CarName,
COUNT(*) as theCount,
MAX(Count(*)) OVER(PARTITION BY 'foo') as MaxInAnyGroup
FROM Cars
GROUP BY CarName
--CTE version
;WITH x AS (
SELECT CarName,
COUNT(*) AS Total
FROM Cars
GROUP BY CarName
)
SELECT x.CarName, x.Total, x2.[Max Total]
FROM x CROSS JOIN (
SELECT [Max Total] = MAX(Total) FROM x
) AS x2;
После выполнения вышеупомянутых запросов я создал индексированное представление для запроса "just group by" выше.Затем я выполнил запрос в индексированном представлении, который выполнил MAX(Count(*)) OVER(PARTITION BY 'foo'
.
СРЕДНИЕ РЕЗУЛЬТАТЫ
Query CPU Reads Duration
--------------------------------------------------------
Group By 15 31 7 ms
Group & Compute 15 31 7 ms
Windowed Functions 14 56 8 ms
Common Table Exp. 16 62 15 ms
Windowed on Indexed View 0 24 0 ms
Очевидно, что это микропроцессор и только слегка поучительныйтак что бери за то, что стоит.