【问题标题】:Accruing over time (non-overlapping) - technique?随着时间的推移积累(非重叠) - 技术?
【发布时间】:2011-05-13 17:41:36
【问题描述】:

我正在尝试找到一种更好的方法来制作水晶报表(其他人的)... 将不重叠的时间按组加起来。 这显然是一个古老的问题...... 有没有获取技巧

  • 调整(开始/结束)时间,每条记录,以消除常见/重叠时间,
  • 在子组内
  • --使用直接 SQL(虽然我发现我可以做 CTE)

假设 Start Time(和/或 Group、SubGroup)的初始 order-by 以及 Start 和 End 是单独的字段。

一种图形示例:

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-only 中得到解决,因为我们不能在数据库服务器上放置任何 proc、临时表等。我试图找出一种使用 CTE 和(重新)诅咒的方法,使用 Group/SubGroup 作为父级,并使用 CASE 来比较当前值与最后一个父级值。这是否敲响了警钟或听起来合理?

Crystal 的能力很多,但这似乎并不适合它。

马克

【问题讨论】:

    标签: sql tuples common-table-expression overlap


    【解决方案1】:

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

    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
    

    【讨论】:

    • 我正在尝试使用我拥有的字段进行编码。运气不太好,但我会继续努力。这就是我所做的...... ;-)
    • 我找到了对一本书的引用,“在 SQL 中开发面向时间的数据库应用程序”(但是,不,我找不到来自 SO 的链接)。第 4 章是关于句点和集合操作的,但我还没有破解它有什么用处。以下是“谷歌是你的朋友”的结果:cs.arizona.edu/~rts/publications.html [乞求“谷歌真的是好朋友吗?”...]
    【解决方案2】:

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

    我假设您在一个子组中有一个包含每天行的表格,因此“Tkt1”有 16 行,“Tkt2”有 18 行等。如果不是这种情况,您只有 start 和每个“Tkt”的结束日期,您必须使用Calendar 表来推断每个范围的行。

    Jeff 的解决方案使用 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 天 ---------- ---------- ---------- ---- 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,其中包含基于您的问题的示例数据。

    然后您可以将每个组相加得出总花费的时间。

    【讨论】:

    • 这非常合适......我一直在从事其他几个项目,而这个项目一直在盯着我(以及想要完整报告的人)。我带来了许多额外的字段,我认为我的部分问题是在处理数百到数千条记录时尝试保持深层分组——占用了太多字段。我将尝试使用这种技术重新工作,看看我是否可以将使用另一种方法获得的 2200(千分之一的元素)记录扩展至 84000。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    • 1970-01-01
    相关资源
    最近更新 更多