SQL Server - Sum Time pr Day

时间:2017-07-24 08:31:07

标签: sql sql-server datetime sql-server-express

我需要一些SQL查询的建议。目前正在使用SQL Server Express 2016.我有两个表。主表称为Dive,详细表称为DiveLog。它是一个记录石油和天然气行业水下设备事件的系统。

以下是表格的详细信息:

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 

对于每次潜水,都会在潜水表中创建一个新的记录。在潜水期间,会记录各种潜水事件。例如:

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,

或者它只能在几分钟内汇总,我会在我的应用程序中将其转换为时间。

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

所以很明显,每次潜水的最大和最小日期必须确定,然后在每个24小时的午夜时段进行总结

任何帮助都会很棒!

1 个答案:

答案 0 :(得分:0)

我认为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个潜水活动不重叠,但可能无关紧要:如果有两个潜水活动记录重叠,活动1从00:02开始并在00:12结束(10分钟) )和活动2从00:07开始并在00:09(2分钟)结束,然后总计为12分钟,此代码将活动1的开始与活动2的结束配对,就好像它是活动的结束1,记录活动1为7分钟。然后它会将活动2记录为类似逻辑的5分钟。总计再次是12分钟,但我基本担心这会混淆开始和结束日期

您的应用实际上也应记录具有专用活动ID的活动;此活动ID与特定活动相关的每个条目的编号相同

"人工日"方法看起来像这样(注意:需要大量的样本数据来正确编写它 - 这已全部写完并且永远不会运行;请通过评论让我知道任何错误。注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