我需要一些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小时的午夜时段进行总结
任何帮助都会很棒!
答案 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