随着时间的推移累积(非重叠) - 技术?

时间:2011-05-13 17:41:37

标签: sql tuples common-table-expression overlap

我正在尝试找一个更好的方法来做一个Crystal Report(别人的)...在组中添加非重叠时间。 这显然是一个古老的问题...... 是否有获取技术

  • 根据记录调整(开始/结束)次数,以消除共同/重叠时间,
  • 在子组内
  • - 使用直接SQL(虽然我发现我可以做CTE)

假设开始时间(和/或组,子组)和开始和结束的初始顺序是单独的字段。

一种图形示例:

Group 1
  SubGroup A
    Tkt 1    |--start&end---|                      "16"
    Tkt 2        |----tart&end----|                "18"
    Tkt 3          |--art&end---|                  "14"
    Tkt 4                            |--S & E -|   "11"

  SubGroup B
    Tkt 5  |-S&E-|                                  "7" 
    Tkt 6          |-S&E-|                          "7" 
    Tkt 7            |-S&E-|                        "7"  
    ...

(equiv adjusted start/end w/in sub-group):
Group 1
  SubGroup A                         (  w/ "elapsed time" of "33"   )
    Tkt 1    |--start&end---|         <- Regular             "16"
    Tkt 2                   |-----|   <- Adjusted "start"     "6"
    Tkt 3                         |   <- Adjusted "start" & "end"   "0"
    Tkt 4                            |--S & E -|  <- Regular "11"

  SubGroup B                         ( w/ "elapsed time"  of "17"   )
    Tkt 5  |-S&E-|                    <- Regular              "7"  
    Tkt 6          |-S&E-|            <- Regular (no overlap) "7"
    Tkt 7                |-|          <- Adjusted "Start"     "3"
    ...

我不是在谈论在这一点上获得总和,只是说明根据之前的记录调整开始/结束。

在报告中,他们针对每个记录执行多个公式,针对在组中的第一个记录上设置的两个变量,然后根据当前记录设置/更新AdjustedStart,AdjustedEnd的值,并将AdjustedStart,AdjustedEnd传递给计算时差的另一个公式,稍后加总。目前的技术很慢,我不能做一个所需的漂亮的交叉表。

我在想/希望这已经在SQL中解决了,因为我们不能在数据库服务器上放置任何proc,临时表等。我试图找出一种方式w / CTE和(重新)诅咒,使用Group / SubGroup作为父母,CASE来比较当前值w / last-parent值。这是响铃还是听起来合理?

水晶的能力很多,但这似乎是一个不适合它的。

马克

2 个答案:

答案 0 :(得分:0)

我正在做这件事......

SELECT
    CUR.subgroup,
    CUR.ticket,
    COALESCE(MAX(PARENT.end_time), CUR.start_time) AS start_time,
    CASE
        WHEN CUR.end_time < MAX(PARENT.end_time) THEN MAX(PARENT.end_time)
        ELSE CUR.end_time
    END
FROM
    My_Table CUR
LEFT OUTER JOIN My_Table PARENT ON
    PARENT.start_time <= CUR.start_time AND
    PARENT.end_time > CUR.start_time AND
    PARENT.ticket <> CUR.ticket AND
    PARENT.subgroup = CUR.subgroup
GROUP BY
    CUR.subgroup,
    CUR.ticket,
    CUR.start_time,
    CUR.end_time

答案 1 :(得分:0)

我很感谢你很久以前问过这个问题,但它对我感兴趣,所以我做了一些研究,找到了Jeff Moden的解决方案;他写了一篇关于分组日期孤岛的文章,您可以在这里找到:Group Islands of Contiguous Dates(需要登录但可以免费注册)。

我假设你在一个子组中每天都有一个包含行的表,所以“Tkt1”有16行,“Tkt2”有18行等。如果不是这样,你只有启动和每个“Tkt”的结束日期,您必须使用Calendar表来推断每个范围的行。

杰夫的解决方案使用ROW_NUMBERDATEDIFF技巧对日期岛进行分组。

WITH Grouped_Dates AS
( -- Find the unique dates and assign them to a group.
  -- The group looks like a date but the date means nothing except that adjacent
  -- dates will be a part of the same group.
 SELECT group_name,
        unique_date = tkt_date,
        date_group  = DATEADD(dd, -ROW_NUMBER() OVER (PARTITION BY group_name ORDER BY group_name, tkt_date), tkt_date)
  FROM t
  GROUP BY group_name, tkt_date
)
-- Now, if we find the MIN and MAX date for each date_group, we'll have the
-- Start and End dates of each group of contiguous daes.  While we're at it,
-- we can also figure out how many days are in each range of days.
SELECT group_name,
       start_date = MIN(unique_date),
       end_date   = MAX(unique_date),
       days       = DATEDIFF(dd,MIN(unique_date),MAX(unique_date))+1
FROM Grouped_Dates
GROUP BY group_name, date_group
ORDER BY group_name, start_date

该查询的结果是

group_name  start_date  end_date    days
----------  ----------  ----------  ----
Group1      2012-01-01  2012-01-22    22
Group1      2012-01-24  2012-02-03    11
Group2      2012-01-09  2012-01-15     7
Group2      2012-01-18  2012-01-27    10

我根据您的问题创建了一个包含示例数据的SQL Fiddle

然后,您可以对每个组进行求和,以计算花费的总时间。