Sql 按小时分组计数(从到)

Sql 按小时分组计数(从到),sql,sql-server,group-by,Sql,Sql Server,Group By,我在查询时遇到了一个问题,该查询必须计算行数并返回数字。关键是我需要最近24小时的数据,除以一个小时的周期。我已经24次使用UNION完成了这个查询,但是单次查询有800多行SQL语句,令人惊讶的是,它只需要3秒钟。我知道我可以按时间分组,但不知道如何正确地分组。我坚信equal查询可能只需要大约20-30行SQL。如果有任何线索,我将不胜感激。这里有一些我提到的简化查询 使用UNION ALL的长查询: DECLARE @CurrentTime datetime = GETDATE(); -

我在查询时遇到了一个问题,该查询必须计算行数并返回数字。关键是我需要最近24小时的数据,除以一个小时的周期。我已经24次使用UNION完成了这个查询,但是单次查询有800多行SQL语句,令人惊讶的是,它只需要3秒钟。我知道我可以按时间分组,但不知道如何正确地分组。我坚信equal查询可能只需要大约20-30行SQL。如果有任何线索,我将不胜感激。这里有一些我提到的简化查询

使用UNION ALL的长查询:

DECLARE @CurrentTime datetime = GETDATE();

--Data from 1 hour
SELECT
----Time
(SELECT CONVERT(VARCHAR(5), (DATEADD(HOUR, -1, @CurrentTime)), 114)) AS [Time],

----Count on 1st table
(SELECT COUNT(T1.[TableFirstId])
FROM [dbo].[Table1] AS T1
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -1, @CurrentTime)) AND @CurrentTime) AS [CountT1],
----Count on 2nd table
(SELECT COUNT(T2.[TableSecondId])
FROM [dbo].[Table2] AS T2
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -1, @CurrentTime)) AND @CurrentTime) AS [CountT2],
----Count on 3rd table
(SELECT COUNT(T3.[TableThirdId])
FROM [dbo].[Table3] AS T3
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -1, @CurrentTime)) AND @CurrentTime) AS [CountT3]

UNION ALL

--Data from 2 hours
SELECT
----Time
(SELECT CONVERT(VARCHAR(5), (DATEADD(HOUR, -2, @CurrentTime)), 114)) AS [Time],

----Count on 1st table
(SELECT COUNT(T1.[TableFirstId])
FROM [dbo].[Table1] AS T1
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -2, @CurrentTime)) AND (DATEADD(HOUR, -1, @CurrentTime))) AS [CountT1],
----Count on 2nd table
(SELECT COUNT(T2.[TableSecondId])
FROM [dbo].[Table2] AS T2
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -2, @CurrentTime)) AND (DATEADD(HOUR, -1, @CurrentTime))) AS [CountT2],
----Count on 3rd table
(SELECT COUNT(T3.[TableThirdId])
FROM [dbo].[Table3] AS T3
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -2, @CurrentTime)) AND (DATEADD(HOUR, -1, @CurrentTime))) AS [CountT3]

UNION ALL

--Data from 3 hours
SELECT
----Time
(SELECT CONVERT(VARCHAR(5), (DATEADD(HOUR, -3, @CurrentTime)), 114)) AS [Time],

----Count on 1st table
(SELECT COUNT(T1.[TableFirstId])
FROM [dbo].[Table1] AS T1
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -3, @CurrentTime)) AND (DATEADD(HOUR, -2, @CurrentTime))) AS [CountT1],
----Count on 2nd table
(SELECT COUNT(T2.[TableSecondId])
FROM [dbo].[Table2] AS T2
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -3, @CurrentTime)) AND (DATEADD(HOUR, -2, @CurrentTime))) AS [CountT2],
----Count on 3rd table
(SELECT COUNT(T3.[TableThirdId])
FROM [dbo].[Table3] AS T3
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -3, @CurrentTime)) AND (DATEADD(HOUR, -2, @CurrentTime))) AS [CountT3]

UNION ALL

--(etc...)
这个问题给了我类似的东西:

Time    |   CountT1   |   CountT2   |   CountT3

21:05   |   3215467   |   3456364   |   3234234

20:05   |   2253221   |   3123123   |   3238291

19:05   |   1231467   |    1232342  |   1123123

18:05   |   3112412   |    6712353  |   1233124

17:05   |   1242141   |   1241142   |   4112426

16:05   |   3123467   |   3456364   |   3234234

15:05   |   3215467   |   3412334   |   3231234

14:05   |   3324467   |   3456123   |   2312334

13:05   |   3215467   |   3456364   |   1112310

12:05   |   3215467   |   3456364   |   1231234

11:05   |   3123127   |   3456364   |   3234234

10:05   |   3215467   |   3456364   |   3234234

09:05   |   3215467   |   3456364   |   3234234

08:05   |   3215467   |   3456364   |   3234234

07:05   |   3215467   |   3456364   |   3234234

06:05   |   3215467   |   3456364   |   3234234

05:05   |   3215467   |   2212214   |   3234234

04:05   |   3215467   |   3126542   |   3234234

03:05   |   3215467   |   3123364   |   3234234

02:05   |   3215467   |   3456364   |   3234234

01:05   |   3215467   |   3456364   |   3234234

00:05   |   3215467   |   3456364   |   3123123

23:05   |   3215467   |   3456364   |   3212313

22:05   |   3223424   |   1232163   |   1235321
我需要通过更简单的查询返回相同的结果,比如:

DECLARE @CurrentTime datetime = GETDATE();

--Data from 24 hours
SELECT

----Count on 1st table
(SELECT COUNT(T1.[TableFirstId])
FROM [dbo].[Table1] AS T1
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT1],
----Count on 2nd table
(SELECT COUNT(T2.[TableSecondId])
FROM [dbo].[Table2] AS T2
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT2],
----Count on 3rd table
(SELECT COUNT(T3.[TableThirdId])
FROM [dbo].[Table3] AS T3
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT3]

FROM [dbo].[Table1] AS T1
GROUP BY DATEPART(HOUR, T1.[IncomingDate])
SELECT COUNT(*) AS T1Count,
CONVERT(VARCHAR(13), IncomingDate, 120) AS IncomingDate
FROM Table1 
GROUP BY CONVERT(VARCHAR(13), IncomingDate, 120)
SELECT T1.IncomingDate, t1.T1Count, t2.T2Count, t3.T3Count FROM
    (SELECT COUNT(*) AS T1Count,
    CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
    from Table1 
    group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T1
FULL OUTER JOIN (SELECT COUNT(*) AS T2Count,
                 CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
                 from Table2 
                 group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T2
    ON T1.IncomingDate = T2.IncomingDate
FULL OUTER JOIN (SELECT COUNT(*) AS T3Count,
                 CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
                 from Table3 
                 group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T3
    ON T1.IncomingDate = T3.IncomingDate
order by T1.IncomingDate

但它没有像我预期的那样工作。有没有人能帮我理解这一点?解决我的问题吗?

此解决方案围绕着将IncomingDate向下截断为所需的每小时增量,然后加入该值的子查询。我正在稍微修改您的需求,并要求所有小时增量都从小时开始,因为这大大简化了查询。 我使用

CONVERT(VARCHAR(13), IncomingDate, 120)
还有其他方法可以做到这一点,但如果我们要根据这个值进行分组,这似乎是一个更好的主意。 要获取一个表的每小时行数,我们有如下查询:

DECLARE @CurrentTime datetime = GETDATE();

--Data from 24 hours
SELECT

----Count on 1st table
(SELECT COUNT(T1.[TableFirstId])
FROM [dbo].[Table1] AS T1
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT1],
----Count on 2nd table
(SELECT COUNT(T2.[TableSecondId])
FROM [dbo].[Table2] AS T2
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT2],
----Count on 3rd table
(SELECT COUNT(T3.[TableThirdId])
FROM [dbo].[Table3] AS T3
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT3]

FROM [dbo].[Table1] AS T1
GROUP BY DATEPART(HOUR, T1.[IncomingDate])
SELECT COUNT(*) AS T1Count,
CONVERT(VARCHAR(13), IncomingDate, 120) AS IncomingDate
FROM Table1 
GROUP BY CONVERT(VARCHAR(13), IncomingDate, 120)
SELECT T1.IncomingDate, t1.T1Count, t2.T2Count, t3.T3Count FROM
    (SELECT COUNT(*) AS T1Count,
    CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
    from Table1 
    group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T1
FULL OUTER JOIN (SELECT COUNT(*) AS T2Count,
                 CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
                 from Table2 
                 group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T2
    ON T1.IncomingDate = T2.IncomingDate
FULL OUTER JOIN (SELECT COUNT(*) AS T3Count,
                 CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
                 from Table3 
                 group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T3
    ON T1.IncomingDate = T3.IncomingDate
order by T1.IncomingDate
现在我们需要做的就是对所有3个表重复,然后在T1.IncomingDate上完全外部连接。结果如下所示:

DECLARE @CurrentTime datetime = GETDATE();

--Data from 24 hours
SELECT

----Count on 1st table
(SELECT COUNT(T1.[TableFirstId])
FROM [dbo].[Table1] AS T1
WHERE T1.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT1],
----Count on 2nd table
(SELECT COUNT(T2.[TableSecondId])
FROM [dbo].[Table2] AS T2
WHERE T2.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT2],
----Count on 3rd table
(SELECT COUNT(T3.[TableThirdId])
FROM [dbo].[Table3] AS T3
WHERE T3.[IncomingDate] BETWEEN (DATEADD(HOUR, -24, @CurrentTime)) AND @CurrentTime) AS [CountT3]

FROM [dbo].[Table1] AS T1
GROUP BY DATEPART(HOUR, T1.[IncomingDate])
SELECT COUNT(*) AS T1Count,
CONVERT(VARCHAR(13), IncomingDate, 120) AS IncomingDate
FROM Table1 
GROUP BY CONVERT(VARCHAR(13), IncomingDate, 120)
SELECT T1.IncomingDate, t1.T1Count, t2.T2Count, t3.T3Count FROM
    (SELECT COUNT(*) AS T1Count,
    CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
    from Table1 
    group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T1
FULL OUTER JOIN (SELECT COUNT(*) AS T2Count,
                 CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
                 from Table2 
                 group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T2
    ON T1.IncomingDate = T2.IncomingDate
FULL OUTER JOIN (SELECT COUNT(*) AS T3Count,
                 CONVERT(VARCHAR(13), IncomingDate, 120) as IncomingDate
                 from Table3 
                 group by CONVERT(VARCHAR(13), IncomingDate, 120)) As T3
    ON T1.IncomingDate = T3.IncomingDate
order by T1.IncomingDate
注意

此查询将针对您的所有数据,我希望您的服务器能够处理它。你可以用几个WHERE子句轻松地把它删减。 如果没有大量的测试数据,我无法在本地机器上测试3路完全外部连接,我太懒了,无法自己创建这些数据。如果没有,你可以使用一个更好的3路外部连接。
此查询将使用较少的SQL提供与查询完全相同的结果

DECLARE @HourTbl TABLE ( HourBegin DATETIME, HourEnd DATETIME)
DECLARE @i INT=0
DECLARE @dtBegin datetime 
DECLARE @dtEnd datetime = GETDATE()

WHILE @i < 24
BEGIN
    SET @i = (@i + 1)
    SET @dtBegin = @dtEnd
    SET @dtEnd = DATEADD(HOUR, -@i, @dtBegin)
    INSERT  INTO @HourTbl
    SELECT   @dtBegin, @dtEnd   
END

;with hourVal (  hourBegin , hourEnd )
as
(

select  hourBegin, hourend
from @HourTbl
)
select CONVERT(VARCHAR(5), hourVal.hourBegin, 114), 
(
select  COUNT(T1.[TableFirstId]) 
from Table1
where T1.[IncomingDate] BETWEEN hourVal.hourBegin, hourVal.hourEnd
),
(
select COUNT(T1.[TableFirstId]) 
from Table2
where T1.[IncomingDate] BETWEEN hourVal.hourBegin, hourVal.hourEnd
)

我们没有你的桌子要测试。你能告诉我它的工作原理有什么不同吗?它是否返回1行?最后一个查询返回24行相同的行,重复的行仅从24小时开始计数。是的,您是对的。这是按小时对简单的SELECT查询进行分组的方法。我需要在子查询中分组,如果我是对的,则在子查询中禁止分组,因为子查询必须只返回一列,而按需要分组另一列。因此,如果我是对的,在子查询中不可能分组。@JakubM我想我对您的要求有了更好的理解。我彻底检查了答案。让我知道它是否有效。非常感谢你的承诺。老实说,我同时找到了解决问题的办法,但这可能不是最好的办法。我构建了基于临时表的查询,我可以在临时表中使用GROUP BY。我的架构师说我必须稍微改进我的查询,所以我需要分析您的提议。目前我正在测试数据库上工作,没有那么多记录,但我不知道查询将如何在prod DB上运行。我会检查你的查询,但我需要一些时间。再次非常感谢你。我将把我为其他人创建的查询粘贴到那里。