【问题标题】:Calculate total time without overlapping time计算不重叠时间的总时间
【发布时间】:2017-10-03 06:55:31
【问题描述】:

MSSQL 2016

目前我有下表:

https://i.stack.imgur.com/W4GX6.png

OwnerName = Jan 这天从 07:00 到 15:30 工作。这意味着他的总工作时间应该是 8.5 小时。然而,当我总结总分钟数时,我得到了更多,因为他有重叠的活动。我如何排除这些重叠的活动并计算他这一天​​的总工作时间: 2017-09-12.

现在,此表不仅包含 2017 年 9 月 12 日的数据,而且每天都有计划的活动。所以查询也应该考虑到这一点。此外,此表中有多个所有者,即 Luc。这也是查询应该处理的问题。

有人可以帮助我吗? :)

编辑:为了让事情更清楚。结果应采用以下格式

|------------------------|------------------|----------------|
|      Ownername         |     Date         |  Time in hours |
|------------------------|------------------|----------------|
|          Jan           |   2017-09-12     |   8.5          | 
|          Luc           |   2017-09-12     |   8.5          |
|          John          |   2017-09-12     |   8.5          |
|          Doe           |   2017-09-11     |   7            |
|          Jan           |   2017-09-13     |   4            | 
|          Doe           |   2017-09-14     |   8.5          |
|          Tom           |   2017-09-14     |   7            |

我目前的猜测是我首先必须确定哪些活动是重叠的。我想我必须使用 BETWEEN 语句来做到这一点。然后使用 CASE 语句不将此时间添加到当天的总时间(以小时为单位)。

【问题讨论】:

  • "这也是查询应该处理的问题。" - 也许是这样 - 但是以什么方式?您是在说应该处理事情,但没有明确说明您要寻找什么结果。您是否正在寻找所有所有者的单一总数?或者您是否正在寻找每个所有者每天的个人总数?或者是其他东西?这些选项中的任何一个都是“处理”所有数据。
  • 请说明您尝试了什么以及阻止您继续进行的实际问题在哪里?现在看来你要求我们做你的工作;)
  • 不,您的要求不清楚。您的解释与您的输入不一致。从您输入的 3 小时或 2.5 小时开始,Luc 的总工作时间是多少。请解释 1 或 2 个示例计算,包括重叠。

标签: sql sql-server


【解决方案1】:

我认为您的问题与 SU​​M 关键字有关。而是尝试使用 DATEDIFF。 这将是准确的,如果您每天有多个记录,请使用 CURSOR,以便您可以唯一地记录每条记录。

例如,在 CURSOR 中使用 DATEDIFF,然后对结果求和

【讨论】:

  • OP 对任何具体问题只字不提
【解决方案2】:

好的,请尝试以下解决方案。它删除包含在其他某个间隔中的间隔,然后使用LAG 窗口函数访问前一行并将间隔更新为不重叠的间隔。然后我们可以简单地执行SUM

WITH
     inputs ( name, date_fr, date_to ) AS (
       select 'Dan'    , cast('07-Jun-17 08:00:00' as DATETIME), cast('07-Jun-17 10:00:00' as DATETIME) union all
       select 'Dan'  , cast('07-Jun-17 11:00:00' as DATETIME), cast('07-Jun-17 12:00:00' as DATETIME) union all
       select 'Jan' , cast('08-Jun-17 08:15:00' as DATETIME), cast('08-Jun-17 15:00:00' as DATETIME) union all
       select 'Jan' , cast('08-Jun-17 08:15:00' as DATETIME), cast('08-Jun-17 10:00:00' as DATETIME) union all
       select 'Jan'    , cast('07-Jun-17 08:30:00' as DATETIME), cast('07-Jun-17 15:00:00' as DATETIME) union all
       select 'Jan'    , cast('07-Jun-17 09:00:00' as DATETIME), cast('07-Jun-17 9:30:00' as DATETIME) union all
       select 'Jan' , cast('07-Jun-17 08:00:00' as DATETIME), cast('07-Jun-17 10:00:00' as DATETIME)
     )
-- End of simulated input (for testing only, not part of the solution).
SELECT name, year(date_fr) year, month(date_fr) month, day(date_fr) day, 
       sum(cast(datediff(minute, date_fr, date_to) as decimal(10,4)))/60
FROM
    (
        SELECT t.name,
               CASE WHEN lag(date_to) over (partition by name order by date_fr) > date_fr 
                    THEN lag(date_to) over (partition by name order by date_fr) 
                    ELSE date_fr 
               END date_fr, 
               t.date_to
        FROM
        (
            SELECT name, date_fr, date_to
            FROM   inputs i1
            WHERE NOT EXISTS (SELECT 1 FROm inputs i2 WHERE i1.name = i2.name and i2.date_fr < i1.date_fr and i2.date_to > i1.date_to) -- this removes fully nested intervals
        ) t
    ) tt
WHERE tt.date_fr < tt.date_to
GROUP BY name, year(date_fr), month(date_fr), day(date_fr)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多