SQL Server分开的重叠日期 [英] SQL Server separate overlapping dates

查看:110
本文介绍了SQL Server分开的重叠日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含以下数据的表:

I have a table with the following data:

如果类型的日期重叠,我想在重叠期间返回单独的一行,因此得到以下结果:

If the dates overlap for a Type, I want to return a separate row for the overlapping period so end up with the following results:

推荐答案

请考虑将范围视为几何线,然后使用SQL Server的几何工具。

Consider treating the ranges as geometric lines and then using SQL Server's geometry tools.

首先,我需要将您的数据放入一个我可以使用的表中:

First, I need to get your data into a table I can work with:

declare @spans table (
    type char(1),
    start datetime,
    stop datetime
);

insert @spans values 
    ('S', '2010-01-01', '2010-01-14'),
    ('S', '2010-01-10', '2010-01-31'),
    ('A', '2010-01-05', '2010-01-30'),
    ('A', '2010-01-24', '2010-02-06'),
    ('T', '2010-01-20', '2010-01-27'),
    ('T', '2010-01-28', '2010-01-30');

不幸的是,SQL Server的空间工具在一方面受到限制。当您需要查询几何值中的单个形状或点时,必须传递索引号才能获取它。在Microsoft推出输出所有形状的TVF之前,我们一直使用数字表来完成工作。

Unfortunately, SQL Server's spatial tools are limited on one respect. When you need to query individual shapes or points inside a 'geometry' value, you have to pass the index number to get it. Until microsoft comes out with a TVF that outputs all the shapes, we resort to a numbers table to get the job done.

用您喜欢的方法来创建数字表:

Swap this out with your preferred method to create a numbers table:

declare     @numbers table (i int);
insert      @numbers    
select      i = row_number() over (order by (select null))
from        @spans a, @spans b;

现在您已准备好进行主查询。

Now you're ready for the main query.

在 geoAggregates中:

In 'geoAggregates':


  • 我将日期转换为浮点值。我在停止值
    中添加一个以使几何在实数空间中工作,而不是在单元之间没有值的
    整数空间中。

  • 我将浮点值转换为几何点

  • 我从这些点中划出线,并且还将点
    合并到一个称为分隔线的几何空间中

  • 我汇总行和汇总拆分器。对于
    行,如果它们重叠,则将它们合并到一个范围中。对于拆分器,
    会将它们进一步压缩为一个集合。

  • I convert the dates to float values. I add one to the stop value to make the geometry work in the real-number space, as opposed to 'integer space' where there are no values between units.
  • I convert to float values to geometric points
  • I make lines out of these points, and I also hold the points together into a single geometric space called 'splitters'
  • I aggregate the lines and I aggregate the splitters. For the lines this merges them into one range if they overlap. For the splitters, it just further condenses them into one collection.

在外部查询中:


  • 我用分割线分割线。拆分器需要一个缓冲区
    来为其提供非零长度,以便实际执行拆分。

  • 我将分割行的集合提取到单独的行中

  • 我将行封装起来以确保它们仅由
    端点表示。

  • 我解析端点以获取浮点值,撤消添加值
    的止损,然后四舍五入以撤消缓冲效果(以及浮点
    的存储效果)。

  • 我将这些浮点值转换回日期表示形式。

  • I split the lines with the splitters. The splitters need a buffer to give them non-zero length in order to actually perform the split.
  • I extract the collections of splitted lines into individual lines
  • I envelope the lines to ensure they are only represented by their endpoints.
  • I parse the endpoints to get the float values, undo the added value for stop, and round these to undo the buffer effects (and the float storage effects).
  • I convert these float values back into date representations.

此处是代码。它将按您的期望输出,除了在 A的第二行中键入o之外。

Here' the code. It outputs as you expect, except for your type-o in the second row of 'A'.

with

    geoAggregates as (

        select      type,
                    lines = geometry::UnionAggregate(line),
                    splitters = geometry::UnionAggregate(splitters)
        from        @spans
        cross apply (select 
                        startF = convert(float, start),
                        stopF = convert(float, stop) + 1
                    ) prepare
        cross apply (select 
                        startP = geometry::Point(startF, 0, 0),
                        stopP = geometry::Point(stopF, 0, 0)
                    ) pointify
        cross apply (select 
                        line = startP.STUnion(stopP).STEnvelope(),
                        splitters = startP.STUnion(stopP)
                    ) lineify
        group by    type 

    )

    select      type, 
                start,
                stop 
    from        geoAggregates ga
    cross apply (select 
                    splitted = ga.lines.STDifference(splitters.STBuffer(0.001))
                ) sp
    join        @numbers n on n.i between 1 and sp.splitted.STNumGeometries()
    cross apply (select 
                    line = sp.splitted.STGeometryN(i).STEnvelope()
                ) l
    cross apply (select 
                    start = convert(datetime, round(l.line.STPointN(1).STX,0)),
                    stop = convert(datetime, round(l.line.STPointN(3).STX - 1,0)) 
                ) dateify
    order by    type, start;

这篇关于SQL Server分开的重叠日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆