SQL 服务器 - 一天总时间

SQL Server - Sum Time pr Day

我需要一些关于 SQL 查询的建议。目前使用 SQL Server Express 2016。我有两个 table。 Master Table 称为 Dive,detail table 称为 DiveLog。它是一个用于记录石油和天然气行业水下设备事件的系统。

以下是 table 的详细信息:

CREATE TABLE [dbo].[Dives](
[DiveNo] [int] IDENTITY(1,1) NOT NULL,
[ROVID] [smallint] NULL,
[ClientID] [int] NULL,
[ProjectID] [int] NULL,
[WorksiteID] [int] NULL,
[TaskID] [int] NULL,
CONSTRAINT [PK_Dives] PRIMARY KEY CLUSTERED 

CREATE TABLE [dbo].[DiveLog](
[LP] [int] IDENTITY(1,1) NOT NULL,
[Time] [datetime] NULL,
[Activity] [smallint] NULL,
[Comment] [varchar](max) NULL,
[DiveNo] [int] NOT NULL,
CONSTRAINT [PK_DiveLog] PRIMARY KEY CLUSTERED 

每次潜水都会创造一项新记录 table。在潜水期间,会记录各种潜水事件。例如:

Time                  Comment
2017-07-01 12:03:22 - Equipment in the water
2017-07-01 12:06:34 - Starting job
2017-07-01 15:03:55 - Job completed
2017-07-01 16:08:01 - Equipment on deck, dive complete

现在我需要创建给定时间段内每天潜水时间的报告。每天可以进行多次潜水,一次潜水可以跨越多天。我需要总结每天 00:00 到 24:00 的潜水时间。详细程度基于分钟

它应该看起来像这样:

Date         Time
2017-07-01 - 23:33,
2017-07-02 - 24:00,
2017-07-03 - 01:00,

或者只能用分钟来概括,我会在我的app里转换成时间

Date         Sum minutes
2017-07-01 - 435,
2017-07-02 - 109,
2017-07-03 - 597,

所以显然必须确定每次潜水的最大和最小日期,然后在午夜打破每 24 小时的时间段总结它

任何帮助都会很棒!

我假设 ACTIVITY 列类似于 'start'、'end'。如果不是,您将不得不找到另一种方法来可靠地识别哪个定时事件是开始,哪个是结束:

SELECT
  start_times.diveno,
  SUM(DATEDIFF(minute, start_times.starttime, end_times.endtime))
FROM 
  (
    SELECT
      diveno,
      [time] as start_time,
      ROW_NUMBER() OVER(PARTITION BY diveno ORDER BY [time] ASC) as start_counter
    FROM
      DiveLog
    WHERE
      activity = 'start_dive'
  ) start_times
  INNER JOIN
  (
    SELECT
      diveno,
      [time] as end_time,
      ROW_NUMBER() OVER(PARTITION BY diveno ORDER BY [time] ASC) as end_counter
    FROM
      DiveLog
    WHERE
      activity = 'end_dive'
  ) end_times
  ON
    start_times.diveno = end_times.diveno AND start_counter = end_counter
GROUP BY
  start_times.diveno

此解决方案假定特定工作的 2 次潜水活动不重叠,但这可能无关紧要:如果记录的两次潜水活动重叠,并且 activity 1 开始于 00:02 并且在 00:12(十分钟)结束,activity 2 从 00:07 开始,在 00:09(2 分钟)结束,那么总时长是 12 分钟,此代码将配对activity 1 的开始和 activity 2 的结束就好像它是 activity 1 的结束一样,并将 activity 1 记录为 7 分钟。然后它还会将 activity 2 记录为类似逻辑的 5 分钟。总时间又是 12 分钟,但我基本担心这是混淆了开始日期和结束日期

真的,您的应用也应该使用专用 activity ID 记录活动;此 activity id 对于与特定 activity

相关的每个条目都是相同的编号

"artificial days" 方法看起来像这样(注意:需要大量示例数据才能正确编写它 - 这些都已经写过了,从来没有 运行;如果有任何错误,请通过注释2:限制报告日期范围的方式是为参数 @searchStartDate 提供值 - 日期时间应该是第一天的午夜,例如“2017-01-01 00:00:00”和 @plusDaysToSearch 在此之后要查看的天数,例如 2017-01-01 之后接下来的 90 天为 90 天):

WITH dates AS (
    SELECT @searchStartDate as d
    UNION ALL
    SELECT d + 1.0 FROM dates WHERE d < @searchStartDate + @plusDaysToSearch --cant go over 100 here without changing the recursion limit
)

SELECT
  dates.d,
  SUM(
    DATEDIFF(
      minute, 
      CASE WHEN dive_times.start_date != dates.d THEN dates.d ELSE dive_times.start_time END, 
      CASE WHEN dive_times.start_date != dates.d THEN dates.d ELSE dive_times.start_time END
    )
  ) as minutes_dived_today
FROM
  dives
  CROSS APPLY
  dates

  LEFT JOIN

  (
    SELECT start_times.diveno, start_time, start_date, end_time, end_date
    FROM
      (
        SELECT
          diveno,
          [time] as start_time,
          convert(date, [time]) as start_date,
          ROW_NUMBER() OVER(PARTITION BY diveno ORDER BY [time] ASC) as start_counter
        FROM
          DiveLog
        WHERE
          activity = 'start_dive'
      ) start_times
      INNER JOIN
      (
        SELECT
          diveno,
          [time] as end_time,
          convert(date, [time]) as start_date,
          ROW_NUMBER() OVER(PARTITION BY diveno ORDER BY [time] ASC) as end_counter
        FROM
          DiveLog
        WHERE
          activity = 'end_dive'
      ) end_times
      ON
        start_times.diveno = end_times.diveno AND
        start_times.start_counter = end_times.end_counter
  ) dive_times
  ON 
    dives.diveno = end_times.diveno AND 
    dates.d BETWEEN dive_times.start_date AND dive_times.end_date

GROUP BY
  dates.d