SQL Server:间隙/孤岛、日期时间、连续块365天块
我有一张这样的桌子:- tblMeterReadings id仪表周期\开始周期\结束金额SQL Server:间隙/孤岛、日期时间、连续块365天块,sql,sql-server,gaps-and-islands,Sql,Sql Server,Gaps And Islands,我有一张这样的桌子:- tblMeterReadings id仪表周期\开始周期\结束金额 1 2014-01-01 00:00 2014-01-01 00:29:59 100.3 212014-01-01 00:30 2014-01-01 00:59:59 50.5 31 2014-01-01 01:00 2014-01-01 01:29:59 70.7 412014-01-01 01:30 2014-01-01 01:59:59 900.1 512014-01-0102:002014-01-
1 2014-01-01 00:00 2014-01-01 00:29:59 100.3
212014-01-01 00:30 2014-01-01 00:59:59 50.5
31 2014-01-01 01:00 2014-01-01 01:29:59 70.7
412014-01-01 01:30 2014-01-01 01:59:59 900.1
512014-01-0102:002014-01-0102:29:59400.0
612014-01-01 02:30 2014-01-01 02:59:59 200.3
7.1 2014-01-01 03:00 2014-01-01 03:29:59 100.8
812014-01-0103:302014-01-0103:59:59140.3 这是一个从“2014-01-01 00:00”到“2014-01-01 3:59:59”的小“连续块” 在实数表中,存在长度为年的“连续块” 我需要找到最近连续365个完整日的时段开始和时段结束(按米列归档) 当我说完成天数时我指的是条目范围从
00:00到23:59的一天。
当我说“连续”时,我的意思是说一定不会有天不见了
我想选择构成此连续完整天数块的所有行
我还需要一个输出,如:
区块\u开始区块\u结束区块的总金额\u
2013-02-26 00:00 2014-02-26 23:59:59 1034234.5
这是我无法理解的,所以如果有人能解决。。。我会留下深刻印象的 您可以尝试以下方法:
Select MIN(period_start) as "block start"
, MAX(period_end) as "block end"
, SUM(amount) as "total amount"
FROM YourTable
GROUP BY datepart(year, period_start)
, datepart(month, period_start)
, datepart(day, period_start)
, datepart(year, period_end)
, datepart(month, period_end)
, datepart(day, period_end)
Having datepart(year, period_start) = datepart(year, period_end)
AND datepart(month, period_start) = datepart(month, period_end)
AND datepart(day, period_start) = datepart(day, period_end)
AND datepart(hour, MIN(period_start)) = 0
AND datepart(minute,MIN(period_start)) = 0
AND datepart(hour, MAX(period_end)) = 23
AND datepart(minute,MIN(period_end)) = 59
因为您的粒度是1秒,所以您需要以1秒的间隔将时段扩展到开始和结束之间的所有日期/时间。要做到这一点,您需要交叉连接数字表(数字表是通过对任意系统视图中的对象ID进行排序而动态生成的,我将其限制为TOP 86400,因为这是一天中的秒数,并且您已经声明您的时间段不会超过一天):
尝试搜索伊兹克-本-甘缺口岛
该时段是如何开始的?这总是半小时从整小时开始吗?如果没有,它能在一天开始,在另一天结束吗?完整的一天-记录一天中每30分钟一次?@JakubKania间隙可能不是半小时,但始终在00:00到23:59:59之间,不会跨越到另一天。@rudym组成完整一天的部分可能不是30分钟,为免生疑问,它可以是从00:00开始读到23:59:59,或者三读一读一读从00:00:00到01:19:59,然后再读一读从01:20:00到3:44:59,最后一读从3:45:00到23:59:59。我认为这并不能解决问题。。。它比那更复杂。看起来它能完成任务。。。非常感谢。86400的意义是什么?你能添加一些评论来帮助我理解发生了什么吗?还有。。。如果你在设计这个,你会做时间跨度为00:00:00->00:30:00,00:30:00到01:00:00,或者,我是怎么做的?86400只是一天中的秒数,这是如果你的周期跨度不超过一天所需的最大数。是的,我建议结束日期时间不包括期间,因此00:00:00->00:30:00,00:30:00->01:00:00
。对于这个特定的查询,它没有多大区别,但对于其他查询,它可能会有很大区别。这篇文章几乎涵盖了我的推理:谢谢。我将更改跨度,以反映您的评论。如果我这样做,您会更改您的查询,还是我应该这样做?
WITH Numbers AS
( SELECT TOP (86400)
Number = ROW_NUMBER() OVER(ORDER BY a.object_id) - 1
FROM sys.all_objects a
CROSS JOIN sys.all_objects b
ORDER BY a.object_id
)
SELECT r.ID, r.meter, dt.[DateTime]
FROM tblMeterReadings r
CROSS JOIN Numbers n
OUTER APPLY
( SELECT [DateTime] = DATEADD(SECOND, n.Number, r.period_start)
) dt
WHERE dt.[DateTime] <= r.Period_End;
WITH Numbers AS
( SELECT TOP (86400)
Number = ROW_NUMBER() OVER(ORDER BY a.object_id) - 1
FROM sys.all_objects a
CROSS JOIN sys.all_objects b
ORDER BY a.object_id
), Grouped AS
( SELECT r.meter,
Amount = CASE WHEN Number = 1 THEN r.Amount ELSE 0 END,
dt.[DateTime],
GroupingSet = DATEADD(SECOND,
-DENSE_RANK() OVER(PARTITION BY r.Meter
ORDER BY dt.[DateTime]),
dt.[DateTime])
FROM tblMeterReadings r
CROSS JOIN Numbers n
OUTER APPLY
( SELECT [DateTime] = DATEADD(SECOND, n.Number, r.period_start)
) dt
WHERE dt.[DateTime] <= r.Period_End
)
SELECT meter,
PeriodStart = MIN([DateTime]),
PeriodEnd = MAX([DateTime]),
Amount = SUM(Amount)
FROM Grouped
GROUP BY meter, GroupingSet
HAVING DATEADD(YEAR, 1, MIN([DateTime])) < MAX([DateTime]);
meter | PeriodStart | PeriodEnd | Amount
------+---------------------+---------------------+----------
1 | 2014-01-01 00:00:00 | 2014-01-01 03:59:59 | 1963