按小时计算行数并包括零

时间:2014-10-20 19:35:43

标签: sql sql-server sql-server-2008 tsql count

我试图计算(按小时)数据库中的条目数。我已成功编写了一个按小时计算的查询,但它省略了零个条目的小时数。我需要将结果包含在零中。我环顾了互联网,并找到了很多建议。我创建了一个视图,其中有一列按日期时间输入分钟。我已经尝试将主表连接到此视图,我得到的结果与没有连接时相同。仍然没有零。想知道如何让这个查询返回零。我正在使用MS SQL 2008 R2。有什么建议吗?

declare @limit datetime;
use InputArchive
set @limit = current_timestamp;
set @limit = DATEADD(hour, -72, @limit);
SELECT DATEADD(hour, datediff(hour, 0, ArchivedItems.RecordCreated), 0) as TimeHour, COUNT(ISNULL((ArchivedItems.RecordCreated),' ')) as NumPerHour
FROM ArchivedItems 
LEFT OUTER JOIN vw_hoursalot
ON vw_hoursalot.dtHr = ArchivedItems.RecordCreated
where InputTypeId = 5 or InputTypeId = 6 or InputTypeId = 8 and (ArchivedItems.RecordCreated >= @limit)
Group BY DATEADD(hour, Datediff(hour, 0, ArchivedItems.RecordCreated), 0)
order by DATEADD(hour, datediff(hour, 0, ArchivedItems.RecordCreated), 0) desc
option (MAXRECURSION 0)

更新:我将小时视图更改为按小时 对不起,但我不确定全视图SQL是什么意思。

出于法律原因,我无法从archivedItems表中输入任何海峡信息,但RecordCreated列是一个海峡时间戳,即'2013-04-05 14:09:59.167'

2 个答案:

答案 0 :(得分:0)

尝试将vw_hoursalot作为最左边的表放在条件中 - 这意味着无论是否找到ArchivedHours中的相应记录,都将返回视图中的所有行。

我再次编辑 - 这次我花时间模拟了一些虚拟数据,我意识到代码中的一个问题,无论是我的还是你的,都是ArchivedItems.RecordCreated列被用作WHERE条件中的过滤器。因此,仅返回具有现有RecordCreated值的记录。

我已将该条件移至JOIN,并针对我模拟的一些非常基本的数据运行下面的查询。假设您的vw_HoursALot视图返回了编号为0-23的二十四个整数,那么这应该可以为您提供所需的数据。

请注意:我假设InputTypeID来自ArchivedItems

WITH -- I used these two CTEs as my dummy data, based on the information in your post
    vw_HoursALot AS 
      (
      SELECT 1 dtHr UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION 
      SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION 
      SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14 UNION SELECT 15 UNION 
      SELECT 16 UNION SELECT 17 UNION SELECT 18 UNION SELECT 19 UNION SELECT 20 UNION 
      SELECT 21 UNION SELECT 22 UNION SELECT 23 UNION SELECT 0 
      ),
    ArchivedItems AS 
      (
        SELECT GETDATE() AS RecordCreated, 5 AS InputTypeID
        UNION SELECT DATEADD(HOUR, -3, GETDATE()), 6 AS InputTypeID
      )


-- this part is actually doing the work
SELECT 
    vw_HoursALot.dtHr,
    COUNT(ArchivedItems.RecordCreated) AS NumPerHour 
FROM 
    vw_hoursalot
     LEFT OUTER JOIN 
    ArchivedItems ON 
        vw_hoursalot.dtHr = DATEPART(hour, ArchivedItems.RecordCreated) AND
        ArchivedItems.RecordCreated >= DATEADD(hour, -72, GETDATE()) AND
          (
            InputTypeId = 5 OR
            InputTypeId = 6 OR 
            InputTypeId = 8 
          ) 
GROUP BY vw_HoursALot.dtHr 
ORDER BY vw_HoursALot.dtHr DESC 
OPTION (MAXRECURSION 0)

答案 1 :(得分:0)

以下是我提出的建议:

declare @limit datetime;
declare @BaseTime datetime
set @BaseTime = '20141020 15:00'; --must be an even hour
set @limit = DATEADD(hour, -72, @BaseTime);
print @Basetime
;WITH
  D1(N) AS (
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
           ),
  D2(N) AS (SELECT 1 FROM D1 a, D1 b),
  Numbers AS (SELECT TOP (100) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1 AS Number FROM D2),
  AllHours AS (SELECT DATEADD(hour,numbers.number,@limit) AS hr FROM Numbers),
  Raw_Data AS (
    SELECT DATEADD(hour,DATEDIFF(hour,@BaseTime,RecordCreated),@BaseTime) AS HourRecorded FROM
    ArchivedItems
    WHERE RecordCreated BETWEEN @limit AND @BaseTime
    AND InputTypeID IN (5,6,8)
    )
SELECT count(Raw_Data.HourRecorded),AllHours.hr
FROM AllHours left outer join Raw_Data on AllHours.hr = Raw_Data.HourRecorded
GROUP BY AllHours.hr
order by AllHours.hr

以下是我用来创建测试数据的内容

;WITH
  D1(N) AS (
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
           ),
  D2(N) AS (SELECT 1 FROM D1 a, D1 b),
  D4(N) AS (SELECT 1 FROM D2 a, D2 b),
  Numbers AS (SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1 AS Number FROM D4)
INSERT INTO ArchivedItems(InputTypeID, RecordCreated) 
SELECT ABS(CAST(CAST(NEWID() AS VARBINARY) % 10 AS INT)), DATEADD(MINUTE, ABS(CAST(CAST(NEWID() AS VARBINARY) % 10000 AS INT)),'20141017')
FROM Numbers
--Make sure there is a gap
DELETE FROM ArchivedItems WHERE RecordCreated BETWEEN '2014-10-20 06:00:00.000' AND '2014-10-20 08:00:00.000'