从特定时间开始的每小时行数

时间:2016-06-06 12:14:20

标签: sql sql-server

为了获取某些报告的数据,我必须知道在特定日期的特定小时开始的表格中每小时插入了多少行。我已经在another question中找到了解决方案的一部分,但我没有设法找到一种方法来适应我的情况。这是我到目前为止编写的代码:

SELECT DATEADD(HOUR, DATEDIFF(HOUR, 0, t.mydatetime), 0) AS HOUR_CONCERNED,
       COUNT(*) AS NB_ROWS
FROM mytable t
WHERE CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, t.mydatetime))) = '2016-06-06'
GROUP BY DATEADD(HOUR, DATEDIFF(HOUR, 0, t.mydatetime), 0) 
ORDER BY HOUR_CONCERNED;

它给了我以下结果:

HOUR_CONCERNED          NB_ROWS
-------------------     --------
2016-06-06 10:00:00     2157
2016-06-06 11:00:00     60740
2016-06-06 12:00:00     66189
2016-06-06 13:00:00     77096
2016-06-06 14:00:00     90039

问题是我找不到在特定时间(例如上午9:30)开始我的结果的方法,并从此时开始获得每小时的行数。换句话说,我正在寻找上午9点30分到10点30分之间,上午10点30分到11点30分之间的行数等。我要找的结果应该是这样的:

HOUR_CONCERNED          NB_ROWS
-------------------     --------
2016-06-06 09:30:00     3550
2016-06-06 10:30:00     33002
2016-06-06 11:30:00     42058
2016-06-06 12:30:00     55008
2016-06-06 13:30:00     72000

是否有一种简单的方法来调整我的查询并获得这些结果?

3 个答案:

答案 0 :(得分:2)

考虑到特定的开始时间,您可以通过查找自开始时间以来的分钟数,然后除以60,然后将此小时数添加回开始时间来获取小时数,例如

DECLARE @StartTime DATETIME2(0) = '20160606 09:30';
WITH DummyData (mydatetime) AS
(   SELECT  TOP 200 DATEADD(MINUTE, ROW_NUMBER() OVER(ORDER BY [object_id]) - 1, @StartTime)
    FROM sys.all_objects
)
SELECT  HoursSinceStart = FLOOR(DATEDIFF(MINUTE, @StartTime, mydatetime) / 60.0),
        Display = DATEADD(HOUR, FLOOR(DATEDIFF(MINUTE, @StartTime, mydatetime) / 60.0), @StartTime),
        Records = COUNT(*)
FROM    DummyData
WHERE   myDateTime >= @StartTime
GROUP BY FLOOR(DATEDIFF(MINUTE, @StartTime, mydatetime) / 60.0)
ORDER BY Display;

给出了:

HoursSinceStart     Display                 Records
0                   2016-06-06 09:30:00     60
1                   2016-06-06 10:30:00     40
2                   2016-06-06 11:30:00     60
3                   2016-06-06 12:30:00     20

我已离开HoursSinceStart列,希望有助于解构Display列中包含的逻辑

这种方法的问题在于,它只会为您提供存在的块的结果,如果您还需要那些不需要使用数字表生成所有时间块的结果,那么请将其连接到您的数据:

您可以使用以下方法快速生成一系列数字:

DECLARE @StartTime DATETIME2(0) = '20160606 09:30';

-- GENERATE 10 ROWS
WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),

-- CROSS JOIN THE 10 ROWS TO GET 100 ROWS
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),

--CROSS JOIN THE 100 ROWS TO GET 10,000 ROWS
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),

--APPLY ROW_NUMBER TO GET A SET OF NUMBERS FROM 0 - 99,999
Numbers (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) - 1 FROM N3)

SELECT *, 
        TimeStart = DATEADD(HOUR, N, @StartTime),
        TimeEnd = DATEADD(HOUR, N + 1, @StartTime)
FROM Numbers;

其中包括:

N   TimeStart               TimeEnd
--------------------------------------------------
0   2016-06-06 09:30:00     2016-06-06 10:30:00
1   2016-06-06 10:30:00     2016-06-06 11:30:00
2   2016-06-06 11:30:00     2016-06-06 12:30:00
3   2016-06-06 12:30:00     2016-06-06 13:30:00
4   2016-06-06 13:30:00     2016-06-06 14:30:00
5   2016-06-06 14:30:00     2016-06-06 15:30:00
6   2016-06-06 15:30:00     2016-06-06 16:30:00
7   2016-06-06 16:30:00     2016-06-06 17:30:00

然后你可以将你的数据加入到这里(你可能还需要一个结束时间);

DECLARE @StartTime DATETIME2(0) = '20160606 09:30',
        @EndTime DATETIME2(0) = '20160606 15:30';

WITH DummyData (mydatetime) AS
(   SELECT  TOP 200 DATEADD(MINUTE, ROW_NUMBER() OVER(ORDER BY [object_id]) - 1, @StartTime)
    FROM sys.all_objects
),
-- GENERATE NUMBERS
N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) - 1 FROM N3),

TimePeriods AS 
(   SELECT  TimeStart = DATEADD(HOUR, N, @StartTime),
            TimeEnd = DATEADD(HOUR, N + 1, @StartTime)
    FROM    Numbers
    WHERE   DATEADD(HOUR, N, @StartTime) < @EndTime
)

SELECT  tp.TimeStart, tp.TimeEnd, Records = COUNT(dd.myDateTime)
FROM    TimePeriods AS tp
        LEFT JOIN DummyData AS dd
            ON dd.mydatetime >= tp.TimeStart
            AND dd.mydatetime < tp.TimeEnd
GROUP BY tp.TimeStart, tp.TimeEnd
ORDER BY tp.TimeStart;

在没有记录的地方返回0:

TimeStart               TimeEnd                 Records
---------------------------------------------------------
2016-06-06 09:30:00     2016-06-06 10:30:00     60
2016-06-06 10:30:00     2016-06-06 11:30:00     60
2016-06-06 11:30:00     2016-06-06 12:30:00     60
2016-06-06 12:30:00     2016-06-06 13:30:00     20
2016-06-06 13:30:00     2016-06-06 14:30:00     0
2016-06-06 14:30:00     2016-06-06 15:30:00     0

答案 1 :(得分:1)

试试这个:

SELECT DATEADD( MINUTE, 30, DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD( MINUTE, -30, t.mydatetime)), 0)) AS HOUR_CONCERNED,
       COUNT(*) AS NB_ROWS
FROM mytable t
WHERE CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, t.mydatetime))) = '2016-06-06'
GROUP BY DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD( MINUTE, -30, t.mydatetime)), 0) 
ORDER BY HOUR_CONCERNED;

我在GROUP BY功能中添加了30分钟的偏移,将9:30视为9:00,将10:30视为10:00,依此类推。在选择部分中,我将该偏移反转以给出适当的间隔。

出于性能原因,查询中的WHERE条件需要更改。您应该过滤范围:

,而不是将时间戳截断到最近的一天
WHERE t.mydatetime >= CONVERT( DATETIME, '2016-06-06' ) AND t.mydatetime < CONVERT( DATETIME, '2016-06-07' )

答案 2 :(得分:0)

你需要在where子句中有 time ,并设置一个大于你要测量的时间吗?此外,您可以使用 { "type": "1", "item": "Order created successfully.", "order_id": "7", "multicast_id": 9215180185089775977, "success": 1, "failure": 0, "canonical_ids": 0, "results": [{ "message_id": "0:1465191236656122%86acb02ff9fd7ecd" }] } 来获取时间。

var formatWFS = new ol.format.WFS();
var formatGML = new ol.format.GML({
featureNS: 'http://geoserver.org/bftchamber',
featureType: 'bft',
srsName: 'EPSG:27700'
});
var transactWFS = function(p,f) {
switch(p) {
case 'insert':
    node = formatWFS.writeTransaction([f],null,null,formatGML);
    break;
case 'update':
    node = formatWFS.writeTransaction(null,[f],null,formatGML);
    break;
case 'delete':
    node = formatWFS.writeTransaction(null,null,[f],formatGML);
    break;
}
s = new XMLSerializer();
str = s.serializeToString(node);
$.ajax('http://localhost:8080/geoserver/wfs',{
    type: 'POST',
    dataType: 'xml',
    processData: false,
    contentType: 'text/xml',
    data: str
    }).done();
}