带有 HAVING 子句的 SQL 查询的 COUNT 个结果

Posted

技术标签:

【中文标题】带有 HAVING 子句的 SQL 查询的 COUNT 个结果【英文标题】:COUNT results from SQL Query with a HAVING clause 【发布时间】:2011-04-15 18:24:42 【问题描述】:

您能否在带有 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 感到困惑...... 我必须找到每个索赔的最早付款 (AppID),如果该付款是该索赔的第一笔付款并且属于当月,则计算它。 【参考方案1】:

COUNTGROUP BY 子句一起使用将为每个组提供一个计数。如果您想计算组数,则必须是单独的查询(如您的 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”有一个“有效”的解决方案。所以我必须给那个人打分。不过,我感谢您的帮助! 已修复。显然,您不能在不命名子查询的情况下从子查询中进行选择。 (而且你不能在WHERE ... IN 语句中使用子查询with a name) 好的,我把它给了你,正如我在 Emtucifor 提出 DateTime 和 BETWEEN 问题后注意到的那样,另一张海报正在使用 BETWEEN。虽然这可能适用于较新的 DATE 数据类型,但也需要考虑时间部分。 @DScott 实际上,他的查询与 BETWEEN 完全相同。他只是明确表示。请参阅我更新的查询,了解包含该月最后一天所有时间的正确方法。 根据 MS SQl Server 2008 Database Development,它建议使用 >= 【参考方案2】:

您也可以使用子查询。

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

【讨论】:

【参考方案3】:

假设您有一个名为 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) &gt; 0,因为column &gt; 0已经排除了NULL。

@ar 和 @bdukes 的查询不需要内部 SELECT 子句中的任何内容,它们可以只是 SELECT 1,这可能会提高性能(没有其他变化)

我希望对 col_payment_issued_date 有一个限制,以便值没有时间部分,例如上午 11:23,否则您的 BETWEEN 子句最终将无法提取整个月的正确数据。

更新

不管怎样,日期格式“20100901”适用于任何地方,适用于任何语言或 DATEFIRST 设置。我鼓励你养成使用它的习惯。 '09/01/2010' 或 '2010/09/01' 等其他格式可能会混淆月份和日期。

@DScott 说:

有一个 tbl_Application,但在这种情况下没有使用。我可以加入它,但我只是计算这个查询的付款,所以它不是必需的。

您介意尝试我的查询并就其与其他方法相比的性能提供反馈吗?我希望即使在查询中有额外的连接,它也能很好地执行。

【讨论】:

感谢您的信息。您对 BETWEEN 问题是正确的,我没有注意到我选择的原始解决方案。既然另一张海报已经纠正了他们的答案,我就选择了那个。有一个 tbl_Application,但在本例中没有使用。我可以加入它,但我只是计算这个查询的付款,所以它不是必需的。 伟大而彻底的回应,@Emtucifor 在网站开发的这个阶段,没有足够的数据来查看性能。我认为表中最多有 100 行,其中 28 行当前包含“有效”数据。【参考方案4】:

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

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

【讨论】:

以上是关于带有 HAVING 子句的 SQL 查询的 COUNT 个结果的主要内容,如果未能解决你的问题,请参考以下文章

如何正确使用带有 COUNT 列的 SQL HAVING 子句?

SQL - 聚合可能不会出现在 WHERE 子句中,除非它位于 HAVING 子句中包含的子查询中

玩转SQL语句之group by 多字段分组查询与having子句,一篇解决你的疑惑!

SQL语句中,为啥where子句不能使用列别名,而order by却可以?

从带有 HAVING 子句的 MySQL 视图中选择返回空结果集

无法在具有聚合值的 HAVING 子句中使用来自子查询表连接的单值列