Выбор строк с помощью предложения HAVING

Предложение HAVING ставит условия в предложении GROUP BY подобно тому, как WHERE взаимодействует с SELECT. Условие поиска WHERE применяется перед операцией группирования, а условие поиска HAVING — после него. Синтаксис предложения HAVING напоминает синтаксис WHERE, за исключением того, что в предложении HAVING не могут содержаться агрегатные функции. Предложения HAVING могут ссылаться на любые элементы, доступные в списке выбора.

Следующий пример группирует таблицу SalesOrderDetail по коду продукта и включает только те группы продуктов, заказы на которые в сумме превышают 1 000 000 долларов и среднее количество заказов на них меньше 3.

USE AdventureWorks2008R2;
GO
SELECT ProductID, AVG(OrderQty) AS AverageQuantity, SUM(LineTotal) AS Total
FROM Sales.SalesOrderDetail
GROUP BY ProductID
HAVING SUM(LineTotal) > $1000000.00
AND AVG(OrderQty) < 3 ;
GO

Обратите внимание, что если в предложение HAVING включается несколько условий, которые объединяются операторами AND, OR или NOT.

Чтобы просмотреть продукты, сумма продаж которых составила более 2 000 000 долларов, выполните следующий запрос:

USE AdventureWorks2008R2;
GO
SELECT ProductID, Total = SUM(LineTotal)
FROM Sales.SalesOrderDetail
GROUP BY ProductID
HAVING SUM(LineTotal) > $2000000.00 ;
GO

Ниже приводится результирующий набор.

ProductID   Total
----------- ----------------------
781         3864606.54937208
969         2010943.97244001
793         2897478.01200001
784         3699803.72383008
780         3880441.60780208
976         2079038.42948
795         2268057.09000002
783         4548164.01783709
779         4170215.3849281
782         5032968.13026809
794         2679200.01336002
753         2006264.4236

(12 row(s) affected)

Если нужно убедиться, что в вычислениях для каждого продукта участвует, по крайней мере, 1 500 элементов, используйте HAVING COUNT(*) > 1500, чтобы исключить продукты, продажи которых составляют менее 1 500 элементов. Запрос выглядит следующим образом:

USE AdventureWorks2008R2;
GO
SELECT ProductID, SUM(LineTotal) AS Total
FROM Sales.SalesOrderDetail
GROUP BY ProductID
HAVING COUNT(*) > 1500 ;
GO

Понимание последовательности, в которой следует расставлять предложения WHERE, GROUP BY и HAVING, помогает создавать эффективные запросы.

  • Предложение WHERE используется для фильтрации строк, полученных в результате операций, которые указаны в предложении FROM.

  • Предложение GROUP BY используется для группирования выходных данных предложения WHERE.

  • Предложение HAVING используется для фильтрации строк сгруппированного результата.

Любое условие поиска, которое применяется до или после операции группирования, лучше указывать в предложении WHERE. Это уменьшает количество строк, для которых выполняется группирование. Единственные условия поиска, которые следует указывать в предложении HAVING, — это те, которые должны применяться после операции группирования.

Оптимизатор запросов Microsoft SQL Server может работать с большей частью таких условий. Если он определил, что условие поиска в предложении HAVING может применяться перед операцией группирования, он так и делает. Оптимизатор запросов может не распознать все условия поиска предложения HAVING, которые могут применяться перед операцией группирования. Рекомендуется указывать все такие условия поиска в предложении WHERE, а не в предложении HAVING.

В следующем примере показано предложение HAVING с агрегатной функцией. В нем строки из таблицы SalesOrderDetail группируются по коду продукта, а затем удаляются продукты, среднее количество заказов на которые меньше пяти.

USE AdventureWorks2008R2;
GO
SELECT ProductID 
FROM Sales.SalesOrderDetail
GROUP BY ProductID
HAVING AVG(OrderQty) > 5
ORDER BY ProductID ;
GO

В этом примере показано предложение HAVING без агрегатной функции. В нем строки в таблице ProductModel группируются по имени и удаляются те строки, названия которых не начинаются с «Mountain».

USE AdventureWorks2008R2;
GO
SELECT pm.Name, AVG(ListPrice) AS 'Average List Price'
FROM Production.Product AS p
JOIN Production.ProductModel AS pm
ON p.ProductModelID = pm.ProductModelID
GROUP BY pm.Name
HAVING pm.Name LIKE 'Mountain%'
ORDER BY pm.Name ;
GO

Обратите внимание, что предложение ORDER BY может использоваться для упорядочивания выходных данных предложения GROUP BY.

См. также

Справочник