Elsewhere 我已经回答了一个类似的日期打包问题
几何策略。即,我解释了日期范围
作为一条线,并利用geometry::UnionAggregate 合并
范围。
不过,您的问题有两个特点。首先,它调用
对于 sql-server-2008。 geometry::UnionAggregate 不是那么
可用。但是,请在以下位置下载 microsoft 库
https://github.com/microsoft/SQLServerSpatialTools 并加载
它作为 clr 程序集添加到您的实例中,并且您拥有它
可用dbo.GeometryUnionAggregate。
但真正让我感兴趣的是
你有几百万行可以使用。所以我认为
我会在这里重复这个策略,但增加了一个技巧
提高它的性能。这种技术会很好用,如果
您有很多相同的 StaffID/日期子集。
首先,让我们建立一个数字表。把这个换成你最喜欢的
方法来做到这一点。
select i = row_number() over (order by (select null))
into #numbers
from @services; -- where i put your data
然后将日期转换为浮点数并使用这些浮点数创建
几何点。
这些点然后可以通过 STUnion 和 STEnvelope 变成线。
您的范围现在表示为几何线,通过以下方式合并它们
UnionAggregate。生成的几何对象“线条”可能包含
多行。但是任何重叠的线都会变成一条线。
select s.StaffID,
s.Date,
linesWKT = geometry::UnionAggregate(line).ToString()
-- If you have SQLSpatialTools installed then:
-- linesWKT = dbo.GeometryUnionAggregate(line).ToString()
into #aggregateRangesToGeo
from @services s
cross apply (select
beginTimeF = convert(float, convert(datetime,beginTime)),
endTimeF = convert(float, convert(datetime,endTime))
) prepare
cross apply (select
beginPt = geometry::Point(beginTimeF, 0, 0),
endPt = geometry::Point(endTimeF, 0, 0)
) pointify
cross apply (select
line = beginPt.STUnion(endPt).STEnvelope()
) lineify
group by s.StaffID,
s.Date;
每个人员 ID/日期组合都有一个“行”对象。但取决于
在您的数据集上,可能有许多相同的“线”对象
在这些组合之间。如果需要工作人员,这很可能是真的
遵循例行程序,并将数据记录到最近的任何地方。
所以得到一个独特的“线条”对象列表。这应该改进
性能。
从中提取“行”内的各个行。将线条包裹起来,
这确保了这些线仅作为它们的端点存储。阅读
端点 x 值并将它们转换回它们的时间表示。
保留 WKT 表示,以便稍后将其重新加入组合。
select lns.linesWKT,
beginTime = convert(time, convert(datetime, ap.beginTime)),
endTime = convert(time, convert(datetime, ap.endTime))
into #parsedLines
from (select distinct linesWKT from #aggregateRangesToGeo) lns
cross apply (select
lines = geometry::STGeomFromText(linesWKT, 0)
) geo
join #numbers n on n.i between 1 and geo.lines.STNumGeometries()
cross apply (select
line = geo.lines.STGeometryN(n.i).STEnvelope()
) ln
cross apply (select
beginTime = ln.line.STPointN(1).STX,
endTime = ln.line.STPointN(3).STX
) ap;
现在只需将解析后的数据加入到 StaffId/Date 组合中。
select ar.StaffID,
ar.Date,
pl.beginTime,
pl.endTime
from #aggregateRangesToGeo ar
join #parsedLines pl on ar.linesWKT = pl.linesWKT
order by ar.StaffID,
ar.Date,
pl.beginTime;