按小时计算行数并包含零
Posted
技术标签:
【中文标题】按小时计算行数并包含零【英文标题】:count rows by hour and include zeroes 【发布时间】:2014-10-20 19:35:43 【问题描述】:我正在尝试(按小时)计算数据库中的条目数。我已经成功编写了一个按小时计数的查询,但它省略了零条目的小时数。我需要包含零的结果。我浏览了互联网,并找到了很多建议。我创建了一个视图,其中有一列按分钟包含日期时间条目。我尝试将主表加入到这个视图中,得到的结果与没有加入时相同。仍然没有零。想知道如何让这个查询返回零。我正在使用 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”
【问题讨论】:
要么颠倒顺序,要么将您的条件更改为 RIGHT OUTER JOIN - 您需要此查询从完整小时列表开始,然后连接到另一端。 右外连接和交换顺序都不起作用,它们都返回了相同的内容,即 2 行,每行有一个计数的结果。应该不止两行 【参考方案1】:尝试将 vw_hoursalot 作为条件中最左侧的表 - 这意味着将返回视图中的所有行,无论是否找到 ArchivedHours 中的相应记录。
我再次编辑了 - 这次我花时间模拟了一些虚拟数据,我意识到我和你的代码中的一个问题是 ArchivedItems.RecordCreated
列被用作过滤器在 WHERE 条件下。因此,只会返回具有现有 RecordCreated
值的记录。
我已将该条件移至 JOIN,并针对我模拟的一些非常基本的数据运行下面的查询。假设您的 vw_HoursALot
视图返回 24 个编号为 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)
【讨论】:
感谢您的快速回复。那也不起作用,我得到一个看起来像这样的结果, Time Hour NumPerHour 1 2013-10-28 08:00:00:000 1 2 2013-10-25 21:00:00:000 1 这些是唯一的我得到两行。而且应该不止这些。 好的,我尝试了另一个示例 - 如果这不起作用,请使用完整视图 SQL 以及 ArchivedItems 表中的一些示例数据来编辑您的问题。 该代码也没有解决问题。我仍然得到没有零计数的回报 当我将一些示例数据放入并仔细查看时,我意识到您的WHERE
子句正在过滤掉ArchivedItems
中没有对应匹配项的任何时间。试试这个最新编辑中的代码。【参考方案2】:
这是我想出的:
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'
【讨论】:
其中很大一部分是创建一个动态小时表。您可以通过预先制作全部或部分来大大缩短它。以上是关于按小时计算行数并包含零的主要内容,如果未能解决你的问题,请参考以下文章