【问题标题】:How to count records by day from specific hour in a range of date using SQL如何使用 SQL 从日期范围内的特定时间按天计算记录
【发布时间】:2012-01-18 17:59:19
【问题描述】:

我有一个日期时间字段,我想按日期计算从 8:00 到 9:00 的所有记录(即:从:01/01/2012 到:01/03/2012)。

例如,如果我有以下数据:

2012-01-01 08:26
2012-01-01 08:40
2012-01-01 09:26
2012-01-01 10:26
2012-01-02 08:06
2012-01-02 09:26
2012-01-02 09:40
2012-01-03 08:30
2012-01-03 10:26

结果应该是这样的:

2012-01-01 2
2012-01-02 1
2012-01-03 1

编辑: 这是我使用@gbn 解决方案得到的(它对我有用)

SELECT    COUNT(*),  convert(varchar(10),ScanDate,101)
FROM    tblSingleBox (nolock)
WHERE    DATEPART(Hour, scandate) = 8
    and (scandate>='01/03/2012' and scandate<'01/05/2012')
GROUP BY    convert(varchar(10),ScanDate,101) 
order by convert(varchar(10),ScanDate,101)

【问题讨论】:

  • 您的意思是 08:00:00.000 到 08:59:59.999?也就是说,是否包括 09:00?
  • sql server 2005,是的 8-8:59:59
  • @Somebody - 请注意,这个严格的查询(这是完全正确的)仍然扫描日期范围内的每条记录。如果您想要更快的查询,您可以改为通过 seek 获得,但查询更复杂。
  • @Dems 非常感谢你的提示,我给你投票了,你的建议。

标签: sql sql-server sql-server-2005


【解决方案1】:

SQL Server 2005 及更早版本

SELECT
   COUNT(*),
   DATEADD(dd, DATEDIFF(dd, 0, SomeDateTime), 0)
   -- SQL Server 2008: CAST(SomeDateTime AS date)
FROM
   SomeTable
WHERE
   DATEPART(Hour, SomeDateTime) = 8
GROUP BY
   DATEADD(dd, DATEDIFF(dd, 0, SomeDateTime), 0);
   -- SQL Server 2008: CAST(SomeDateTime AS date);

MySQL:

SELECT
   COUNT(*),
   DATE(SomeDateTime)
FROM
   SomeTable
WHERE
   HOUR(SomeDateTime) = 8
GROUP BY
   DATE(SomeDateTime);

【讨论】:

  • 如果您只过滤该小时,它将计算该特定小时内的所有天数
  • 谢谢,但我还需要一个日期范围,我该怎么做?
  • @gbn - 我认为这将需要完全扫描(表或索引)而不是搜索?由于 DATEPART() 使用?
  • @Dems:正确。缺少计算列,如果没有其他人工制品,我看不到更好的方法
  • @Somebody:在 WHERE 子句中添加更多条件
【解决方案2】:

在这种情况下,最简单的代码和最快的代码可能会有很大差异,并且可能取决于数据集的大小。

我怀疑最快的方法是加入日历和过滤器。在这种情况下,我会在开始之前制作一个日历,但我建议一个永久的......

CREATE TABLE #calendar (
  date AS DATETIME
)
INSERT INTO #calendar SELECT '2011-12-31' UNION ALL SELECT '2012-01-01'
            UNION ALL SELECT '2012-01-02' UNION ALL SELECT '2012-01-03'
            UNION ALL SELECT '2012-01-04' UNION ALL SELECT '2012-01-05'

SELECT
  calendar.date,
  COUNT(*)
FROM
  yourTable
INNER JOIN
  #calendar    AS calendar
    ON  yourTable.DateTimeField >= calendar.date + @minTime
    AND yourTable.DateTimeField <  calendar.date + @maxTime
WHERE
      calendar.date >= @startDate
  AND calendar.date <= @endDate
GROUP BY
  calendar.date

这应该会产生对索引最友好的查询,因此对于任何合理大小的数据都非常有效。

注意:

calendar.date + @Time 部分会有所不同。你刚才说的是 MS SQL Server,所以更像是……

    ON  yourTable.DateTimeField >= DATEADD(hour, @minHour, calendar.date)
    AND yourTable.DateTimeField <  DATEADD(hour, @maxHour, calendar.date)

【讨论】:

  • 这避免了使用 DATEPART() 和其他函数来产生index friendly query。这意味着只处理索引的相关部分,而不是扫描整个索引或表。
【解决方案3】:

SQL Server 2005

IF OBJECT_ID('tempdb.dbo.#DATES') IS NOT NULL
    DROP TABLE #DATES

CREATE TABLE #DATES
    (   LogDate smalldatetime   )

INSERT INTO #DATES
    (   LogDate )
            SELECT  '2012-01-01 08:26'
UNION SELECT '2012-01-01 08:40'
UNION SELECT '2012-01-01 09:26'
UNION SELECT '2012-01-01 10:26'
UNION SELECT '2012-01-02 08:06'
UNION SELECT '2012-01-02 09:26'
UNION SELECT '2012-01-02 09:40'
UNION SELECT '2012-01-03 08:30'
UNION SELECT '2012-01-03 10:26'
UNION SELECT '2012-01-03 15:26'

DECLARE @nStartHour smallint
DECLARE @nEndHour smallint

SET @nStartHour = 15
SET @nEndHour = 16

SELECT  CONVERT(varchar, LogDate, 101), COUNT(*)
FROM        #DATES
WHERE       DATEPART(hour,LogDate) BETWEEN @nStartHour AND (@nEndHour - 1)
GROUP BY CONVERT(varchar, LogDate, 101)

【讨论】:

    猜你喜欢
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 2016-05-18
    • 2012-03-23
    • 2021-02-03
    • 1970-01-01
    • 2020-04-18
    • 2011-02-05
    相关资源
    最近更新 更多