在这样的msdn状态下找到的文档中,我开始学习SQL Server
HAVING通常与GROUP BY子句一起使用。如果不使用GROUP BY,则存在一个隐式的单个聚合组。
这使我认为我们可以不使用groupBy子句而使用having,但是当我尝试进行查询时,我将无法使用它。
我有一张这样的桌子
CREATE TABLE [dbo].[_abc]
(
[wage] [int] NULL
) ON [PRIMARY]
GO
INSERT INTO [dbo].[_abc] (wage)
VALUES (4), (8), (15), (30), (50)
GO
现在,当我运行此查询时,我得到一个错误
select *
from [dbo].[_abc]
having sum(wage) > 5
错误:
答案 0 :(得分:4)
文档正确无误;也就是说,您可以运行以下语句:
select sum(wage) sum_of_all_wages
, count(1) count_of_all_records
from [dbo].[_abc]
having sum(wage) > 5
您的语句不起作用的原因是由于select *
,这意味着选择每列的值。如果没有group by
,则所有记录都将汇总;也就是说,您在结果集中只能获得1条记录,该记录必须代表每条记录。因此,您只能*包括通过将聚合函数应用于列而提供的值;不是列本身。
*当然,您也可以提供常量,因此select 'x' constant, count(1) cnt from myTable
可以使用。
在没有分组依据的情况下,我能想到的用例并不多,但可以肯定地做到了,如上所示。
注意:如果您希望所有工资都高于5的行,则可以使用where
子句:
select *
from [dbo].[_abc]
where wage > 5
同样,如果您希望所有工资的总和大于5,则可以这样做
select sum(wage) sum_of_wage_over_5
from [dbo].[_abc]
where wage > 5
或者如果您想比较5岁以下的工资总和:
select case when wage > 5 then 1 else 0 end wage_over_five
, sum(wage) sum_of_wage
from [dbo].[_abc]
group by case when wage > 5 then 1 else 0 end
having
才能使用聚合函数?不。您可以运行select sum(wage) from [dbo].[_abc]
。当使用不带group by
子句的聚合函数时,就好像您是按常量分组一样。即select sum(wage) from [dbo].[_abc] group by 1
。
该文档仅意味着,尽管通常您会有一个having
语句和一个group by
语句,但是可以排除group by
/在这种情况下可以排除having
语句,像select
语句一样,将您的查询视为已指定group by 1
很难想到很多好的用例,因为您只返回了一行,而having
语句是对此的过滤器。
一个用例是您编写代码以监视某些软件的许可证;如果您的用户数少于每用户许可数,那么一切都很好/您不希望看到结果,因为您不在乎。如果您有更多的用户,您想了解它。例如
declare @totalUserLicenses int = 100
select count(1) NumberOfActiveUsers
, @totalUserLicenses NumberOfLicenses
, count(1) - @totalUserLicenses NumberOfAdditionalLicensesToPurchase
from [dbo].[Users]
where enabled = 1
having count(1) > @totalUserLicenses
是,不是。拥有过滤汇总数据的功能。选择说什么带回的列/信息。因此,您必须问“结果会是什么样?”即,鉴于我们必须有效地应用group by 1
来利用having
语句,SQL应该如何解释select *
?由于您的表只有一列,因此它将转换为select wage
;但我们有5行,因此wage
的5个不同值,结果中只有1行显示此内容。
我猜你可能会说:“如果它们的总和大于5,我想返回所有行;否则,我不想返回任何行”。您的要求是否可以通过多种方式实现?其中之一是:
select *
from [dbo].[_abc]
where exists
(
select 1
from [dbo].[_abc]
having sum(wage) > 5
)
但是,我们必须编写代码来满足要求,而不是期望代码理解我们的意图。
思考having
的另一种方法是作为应用于子查询的where
语句。即您的原始声明有效地显示为:
select wage
from
(
select sum(wage) sum_of_wage
from [dbo].[_abc]
group by 1
) singleRowResult
where sum_of_wage > 5
该操作将无法运行,因为wage
无法用于外部查询;仅返回sum_of_wage
。
答案 1 :(得分:1)
HAVING
(无GROUP BY
子句是完全有效的,但这是您需要了解的内容:
GROUP BY
条件匹配零行,隐式WHERE
也将只返回一行HAVING
将根据条件保留或消除该单行SELECT
子句中的任何列都需要包装在聚合函数中这意味着您可以这样做:
SELECT SUM(wage)
FROM employees
HAVING SUM(wage) > 100
-- One row containing the sum if the sum is greater than 5
-- Zero rows otherwise
甚至是这样:
SELECT 1
FROM employees
HAVING SUM(wage) > 100
-- One row containing "1" if the sum is greater than 5
-- Zero rows otherwise
当您有兴趣检查是否找到聚合的匹配项时,通常使用此构造:
SELECT *
FROM departments
WHERE EXISTS (
SELECT 1
FROM employees
WHERE employees.department = departments.department
HAVING SUM(wage) > 100
)
-- all departments whose employees earn more than 100 in total
答案 2 :(得分:0)
在SQL中,您不能直接返回聚合函数列。您需要对非聚集字段进行分组
如下例所示
USE AdventureWorks2012 ;
GO
SELECT SalesOrderID, SUM(LineTotal) AS SubTotal
FROM Sales.SalesOrderDetail
GROUP BY SalesOrderID
HAVING SUM(LineTotal) > 100000.00
ORDER BY SalesOrderID ;
在您的情况下,您的表没有标识列,它应该如下所示
Alter _abc
Add Id_new Int Identity(1, 1)
Go