使用HAVING子句计算SQL查询结果的数量

13
你能否在HAVING子句中使用COUNT函数,以便COUNT返回行数?但是当我尝试时,它返回的是ID在表中出现的次数。以下是查询语句:
SELECT col_appid, min(col_payment_issued_date) as PayDate  
FROM tbl_ui_paymentstubs  
WHERE isnull(col_payment_amount,0) > 0  
GROUP BY col_appid  
HAVING min(col_payment_issued_date) >= '09/01/2010' and min(col_payment_issued_date) <= '09/30/2010'

我返回了6行,这很好,但我只想返回数字6。

我发现我可以用这种方式实现,但想知道是否有另一种更优雅的方法:

WITH Claims_CTE(AppID, PayDate) as
(  
 SELECT col_appid, min(col_payment_issued_date) as PayDate
 FROM tbl_ui_paymentstubs
 WHERE isnull(col_payment_amount,0) > 0
 GROUP BY col_appid
 HAVING min(col_payment_issued_date) >= '09/01/2010' and min(col_payment_issued_date) <= '09/30/2010'
)  
 SELECT count(AppID) as Amount from Claims_CTE

`


你能否发布一下你的表结构?我对为什么在这个查询中使用min感到困惑... - armonge
我必须为每个索赔(AppID)找到最早的付款,并且如果该付款是该索赔的第一笔且在当前月内,则计数。 - D.S.
4个回答

17

使用带有GROUP BY子句的COUNT将为每个组提供计数。如果您想要获得组数的计数,则必须进行单独查询(例如您的CTE示例)。

我只会使用一个简单的子查询,而不是CTE:

SELECT COUNT(*) FROM 
 (SELECT col_appid, min(col_payment_issued_date) as PayDate  
  FROM tbl_ui_paymentstubs  
  WHERE isnull(col_payment_amount,0) > 0  
  GROUP BY col_appid  
  HAVING
     min(col_payment_issued_date) >= '09/01/2010'
     and min(col_payment_issued_date) <= '09/30/2010') Claims

这个例子不幸地会抛出一个错误。我知道你的意思,但是“ar”有一个“可行”的解决方案。所以我必须把分数给那个人。虽然感谢你的帮助! - D.S.
已解决。显然,您不能在不为子查询命名的情况下从子查询中进行选择。(并且您不能在具有名称的WHERE ... IN语句中使用子查询) - bdukes
好的,我给了你。在Emtucifor提出DateTime和BETWEEN问题之后,我注意到另一个帖子正在使用BETWEEN。虽然这可能适用于较新的DATE数据类型,但时间部分也需要考虑。 - D.S.
@DScott实际上,他的查询与BETWEEN完全相同。他只是明确地表达了出来。请查看我更新的查询以包含每个月最后一天的所有时间的正确方法。 - ErikE
根据MS SQL Server 2008数据库开发,建议使用>= <=,因为它处理较新的datetime2数据类型。它指出:“每当查询时间数据时,应尝试使用小于谓词以避免依赖特定的秒分数精度”,然后提到使用您提到的日期格式YYYYMMDD。我使用DD/MM/YYYY格式,因为这是通过内置日期控件在SSRS中传递的,但需要养成使用YYYYMMDD的习惯。 - D.S.

4
您也可以使用子查询。
SELECT count(*) as Amount
FROM (
    SELECT col_appid FROM tbl_ui_paymentstubs
    WHERE isnull(col_payment_amount,0) > 0
    GROUP BY col_appid
    HAVING min(col_payment_issued_date) BETWEEN '09/01/2010' AND '09/30/2010'
) Claims

2
假设您有一个名为App的表,其中包含col_appid值的唯一列表,此查询也可以正常工作,并且可能性能更好:
SELECT Count(*)
FROM
   App A
   CROSS APPLY (
      SELECT TOP 1 col_payment_issued_date
      FROM tbl_ui_paymentstubs P
      WHERE
         P.col_payment_amount > 0
         AND A.col_appid = P.col_appid
      ORDER BY col_payment_issued_date
   ) X
WHERE
   X.col_payment_issued_date >= '09/01/2010'
   AND X.col_payment_issued_date < '10/01/2010'

如果没有App表,您可以替换为(SELECT DISTINCT col_appid FROM tbl_ui_paymentstubs) A,但性能可能会有所下降。与给出的其他查询相比,它仍然是一个竞争者。
其他注意事项:
- 您不需要执行isnull(column, 0) > 0,因为column > 0已经排除了NULL值。 - @ar和@bdukes的查询不需要在内部SELECT子句中添加任何内容,它们可以只是SELECT 1,这可能是性能的提升(其他内容不变)。 - 我希望col_payment_issued_date上有约束条件,以便值没有时间部分,例如11:23 AM,否则您的BETWEEN子句最终将无法正确地获取整个月的数据。
更新:
- 就价值而言,日期格式“20100901”将在任何地方都起作用,无论语言或DATEFIRST设置如何。我鼓励您养成使用它的习惯。其他格式,如“09/01/2010”或“2010/09/01”等,可能会混淆月份和日期。
@DScott说:
- 有一个tbl_Application表,但在这种情况下未使用。我可以加入它,但我只是计算此查询的付款,因此不需要。
您介意尝试我的查询并就其性能与其他方法进行反馈吗?我希望即使在查询中有额外的连接,它也能表现得相当好。

谢谢提供信息。你说的BETWEEN问题是正确的,我没有注意到原始解决方案中有这个问题。现在其他回答者已经纠正了他们的答案,我选择了那个答案。虽然有一个tbl_Application表,但在这种情况下它没有被使用。我可以加入它,但是因为这个查询只是计算付款,所以不需要它。 - D.S.
很好的、全面的回复,@Emtucifor - bdukes
1
在网站开发的这个阶段,还没有足够的数据来查看性能。我认为最多只有100行数据,其中28行目前包含“有效”数据。 - D.S.

0

在 Oracle 中使用以下查询来计算重复记录。

SELECT Column1 , count(*) Num
FROM TABLE_NAME whe   
GROUP BY Column1 
HAVING count(*) > 1  
ORDER BY num desc;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接