我编写了一个查询,根据给定的日期范围对每小时的行数进行分组。
SELECT CONVERT(VARCHAR(8),TransactionTime,101) + ' ' + CONVERT(VARCHAR(2),TransactionTime,108) as TDate,
COUNT(TransactionID) AS TotalHourlyTransactions
FROM MyTransactions WITH (NOLOCK)
WHERE TransactionTime BETWEEN CAST(@StartDate AS SMALLDATETIME) AND CAST(@EndDate AS SMALLDATETIME)
AND TerminalId = @TerminalID
GROUP BY CONVERT(VARCHAR(8),TransactionTime,101) + ' ' + CONVERT(VARCHAR(2),TransactionTime,108)
ORDER BY TDate ASC
显示如下内容:
02/11/20 07 4
02/11/20 10 1
02/11/20 12 4
02/11/20 13 1
02/11/20 14 2
02/11/20 16 3
给出交易数量和当天给定的小时数。
如何显示当天的所有小时数 - 从0到23,如果没有值,则显示0?
感谢。
使用下面的tvf为我工作了一天,但是我不知道如何让它适用于日期范围。
使用24小时的临时表:
-- temp table to store hours of the day
DECLARE @tmp_Hours TABLE ( WhichHour SMALLINT )
DECLARE @counter SMALLINT
SET @counter = -1
WHILE @counter < 23
BEGIN
SET @counter = @counter + 1
--print
INSERT INTO @tmp_Hours
( WhichHour )
VALUES ( @counter )
END
SELECT MIN(CONVERT(VARCHAR(10),[dbo].[TerminalTransactions].[TransactionTime],101)) AS TDate, [@tmp_Hours].[WhichHour], CONVERT(VARCHAR(2),[dbo].[TerminalTransactions].[TransactionTime],108) AS TheHour,
COUNT([dbo].[TerminalTransactions].[TransactionId]) AS TotalTransactions,
ISNULL(SUM([dbo].[TerminalTransactions].[TransactionAmount]), 0) AS TransactionSum
FROM [dbo].[TerminalTransactions] RIGHT JOIN @tmp_Hours ON [@tmp_Hours].[WhichHour] = CONVERT(VARCHAR(2),[dbo].[TerminalTransactions].[TransactionTime],108)
GROUP BY [@tmp_Hours].[WhichHour], CONVERT(VARCHAR(2),[dbo].[TerminalTransactions].[TransactionTime],108), COALESCE([dbo].[TerminalTransactions].[TransactionAmount], 0)
给我一个结果:
TDate WhichHour TheHour TotalTransactions TransactionSum
---------- --------- ------- ----------------- ---------------------
02/16/2010 0 00 4 40.00
NULL 1 NULL 0 0.00
02/14/2010 2 02 1 10.00
NULL 3 NULL 0 0.00
02/14/2010 4 04 28 280.00
02/14/2010 5 05 11 110.00
NULL 6 NULL 0 0.00
02/11/2010 7 07 4 40.00
NULL 8 NULL 0 0.00
02/24/2010 9 09 2 20.00
那么如何才能正确分组?
另一个问题是,有些日子里没有交易,现在也需要出现。
感谢。
答案 0 :(得分:4)
首先构建23小时表,对事务表执行外连接。出于同样的目的,我使用表值函数:
create function tvfGetDay24Hours(@date datetime)
returns table
as return (
select dateadd(hour, number, cast(floor(cast(@date as float)) as datetime)) as StartHour
, dateadd(hour, number+1, cast(floor(cast(@date as float)) as datetime)) as EndHour
from master.dbo.spt_values
where number < 24 and type = 'p');
然后我可以在需要获得“每小时”基础数据的查询中使用TVF,即使数据中缺少间隔:
select h.StartHour, t.TotalHourlyTransactions
from tvfGetDay24Hours(@StartDate) as h
outer apply (
SELECT
COUNT(TransactionID) AS TotalHourlyTransactions
FROM MyTransactions
WHERE TransactionTime BETWEEN h.StartHour and h.EndHour
AND TerminalId = @TerminalID) as t
order by h.StartHour
<强>更新强>
在任意日期之间返回24小时的TVF示例:
create function tvfGetAnyDayHours(@dateFrom datetime, @dateTo datetime)
returns table
as return (
select dateadd(hour, number, cast(floor(cast(@dateFrom as float)) as datetime)) as StartHour
, dateadd(hour, number+1, cast(floor(cast(@dateFrom as float)) as datetime)) as EndHour
from master.dbo.spt_values
where type = 'p'
and number < datediff(hour,@dateFrom, @dateTo) + 24);
请注意,由于master.dbo.spt_values仅包含2048个数字,因此该函数在2048小时之后的日期之间不起作用。
答案 1 :(得分:3)
您刚刚发现了NUMBERS表的值。您需要创建一个包含单个列的表,其中包含数字0到23。然后使用OUTER连接再次加入此表,以确保始终返回24行。
答案 2 :(得分:1)
所以回到使用Remus的原始函数,我在递归调用中重用它并将结果存储在临时表中:
DECLARE @count INT
DECLARE @NumDays INT
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
DECLARE @CurrentDay DATE
DECLARE @tmp_Transactions TABLE
(
StartHour DATETIME,
TotalHourlyTransactions INT
)
SET @StartDate = '2000/02/10'
SET @EndDate = '2010/02/13'
SET @count = 0
SET @NumDays = DateDiff(Day, @StartDate, @EndDate)
WHILE @count < @NumDays
BEGIN
SET @CurrentDay = DateAdd(Day, @count, @StartDate)
INSERT INTO @tmp_Transactions (StartHour, TotalHourlyTransactions)
SELECT h.StartHour ,
t.TotalHourlyTransactions
FROM tvfGetDay24Hours(@CurrentDay) AS h
OUTER APPLY ( SELECT COUNT(TransactionID) AS TotalHourlyTransactions
FROM [dbo].[TerminalTransactions]
WHERE TransactionTime BETWEEN h.StartHour AND h.EndHour
AND TerminalId = 4
) AS t
ORDER BY h.StartHour
SET @count = @Count + 1
END
SELECT *
FROM @tmp_Transactions
答案 3 :(得分:0)
按日期分组('小时',时间)。显示那些没有值的小时你必须加入一个时间表来对抗分组(coalesce(transaction.amount,0))
答案 4 :(得分:0)
之前我遇到过这个问题的版本。最好的建议是设置一个表(临时的或不是临时的)与一天中的小时数,然后通过datepart('h',timeOfRecord)对该表和group进行外连接。
我不记得为什么,但可能由于缺乏灵活性,因为需要另一个表,我最终使用的方法是按照我想要的任何日期部分进行分组并按日期时间排序,然后循环执行填充任何用0跳过的空格。这种方法对我来说很有效,因为我不依赖于数据库为我完成所有工作,而且为它编写自动化测试也更容易。
答案 5 :(得分:0)
第1步,创建#table或CTE以生成小时数表。外循环为天和内循环小时0-23。这应该是3列日期,天,小时。
第2步,将您的主查询写为还有天数和小时列,并将其别名,以便您可以加入。 CTE必须高于这个主要问题,并且枢轴应该在CTE内部,以使其自然地工作。
第3步,从第1步表中选择并左连接此主查询表
ON A.[DATE] = B.[DATE]
AND A.[HOUR] = B.[HOUR]
您也可以按照
等日期列创建订单 ORDER BY substring(CONVERT(VARCHAR(15), A.[DATE], 105),4,2)
<强> Guidlines 强>
然后,这将为您提供小时和天数的所有数据,包括零小时的零,没有匹配,使用isnull([col1],0) as [col1]
。
您现在可以根据日期和时间绘制事实。