【问题标题】:SQL group by day, with countSQL 按天分组,有计数
【发布时间】:2026-01-20 23:55:01
【问题描述】:

我在 SQL Server 中有一个如下所示的日志表:

CREATE TABLE [dbo].[RefundProcessLog](
 [LogId] [bigint] IDENTITY(1,1) NOT NULL,
 [LogDate] [datetime] NOT NULL,
 [LogType] [varchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 [RefundId] [int] NULL,
 [RefundTypeId] [smallint] NULL,
 [LogMessage] [varchar](1000) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 [LoggedBy] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
 CONSTRAINT [PK_RefundProcessLog] PRIMARY KEY CLUSTERED 
(
 [LogId] ASC
) ON [PRIMARY]
) ON [PRIMARY]

GO

我想要的是一个结果列表,表示每天处理了多少个不同的refundid,并丢弃任何NULL。

我需要编写什么 SQL 才能产生这些结果?

【问题讨论】:

    标签: sql sql-server group-by aggregate


    【解决方案1】:
    Select count(*), LogDate, refundid from RefundProcessLog
    where refundid is not null
    group by LogDate, refundid
    

    编辑:

    如果您不希望它被退款分解,或者删除 RefundID

    【讨论】:

    • 这行不通。它将返回一行,其中包含每个不同的refundid 值的计数,这不是我们想要的。
    【解决方案2】:

    在 SqlServer 中,它会是这样的:

    select datepart(YEAR, [LogDate]), datepart(MONTH, [LogDate]), datepart(DAY, [LogDate]), count(refundid) as [Count]
    from [RefundProcessing]
    group by datepart(YEAR, [LogDate]), datepart(MONTH, [LogDate]), datepart(DAY, [LogDate])
    

    【讨论】:

      【解决方案3】:

      您使用的是哪个数据库供应商?不管是什么,用适当的结构替换下面的“DateOnly(LogDate)”,以从 logdate 列值中提取日期部分(去掉时间),然后试试这个:

      Select [DateOnly(LogDate)], Count Distinct RefundId
      From RefundProcessLog
      Group By [DateOnly(LogDate)]
      

      在 Sql server 中,例如,适当的构造是:

      Select DateAdd(day, 0, DateDiff(day, 0, LogDate)), Count(Distinct RefundId)
      From RefundProcessLog
      Group By DateAdd(day, 0, DateDiff(day, 0, LogDate))
      

      【讨论】:

        【解决方案4】:
        SELECT COUNT(RefundId), DateOnly(LogDate) LoggingDate
        FROM RefundProcessLog
        GROUP BY DateOnly(LogDate)
        

        “DateOnly”特定于您的 SQL 数据库,您没有指定。

        对于 SQL Server,您可以将 DateAdd(dd,0, DateDiff(dd,0,LogDate)) 用于“DateOnly”

        【讨论】:

        • 您可能希望在结果集中包含日期。如所写,这将给出refundIds 的数量,但无法知道哪个数字出现在哪一天。
        【解决方案5】:
        select cast(LogDate as date) as LogDate, count(refundId) as refundCount
        from yourTable
        group by cast(LogDate as date)
        

        根据您使用的 SQL 方言,您可能需要将 CAST 更改为其他内容。该表达式应将 LogDate 转换为仅日期值。

        另外,如果您说“不同的refundId”,因为您可能只想计算一次refundId 的重复值,请使用count(DISTINCTrefundId)

        【讨论】:

        • 这样的性能应该远远优于公认的解决方案,其中涉及到字符串转换。
        • @James 同意性能与字符串转换的关系。但是您(或任何人)是否知道性能与使用 DateAdd(day, 0, DateDiff(day, 0, LogDate)) 的 charles-bretana 的解决方案的比较
        • @Fonnae,我没有测量,但我希望这会比其他答案稍微快一些,因为它正在做一些通用的日期操作(可能比这个 CAST 慢),而且我我很确定这些操作会导致以午夜为时间的完整 DATETIME,而此解决方案使用较小的 DATE 类型进行分组,使用起来应该更快。
        【解决方案6】:

        我喜欢 (MS SQL) 中的这种方法:

        SELECT 
          Convert(char(8), LogDate, 112),
          count(distinct RefundId)
        FROM RefundProcessing
        GROUP BY Convert(char(8), LogDate, 112)
        

        【讨论】:

          【解决方案7】:

          SQL Server 2008 引入了date 数据类型,这使得以下操作成为可能:

          select convert(date, LogDate),
                ,count(refundid) AS 'refunds'
            from RefundProcessing
          group by convert(date,LogDate)
          order by convert(date,LogDate)
          

          【讨论】: