用于返回时间轴结果集的 Sql 查询

Nei*_*son 2 sql sql-server group-by

我认为描述我正在寻找的内容的最佳方法是显示数据表以及我想要从查询返回的内容。这是 SQL Server 中的一个简单数据表:

JobNumber TimeOfWeigh 
100       01/01/2014 08:00 
100       01/01/2014 09:00 
100       01/01/2014 10:00 
200       01/01/2014 12:00 
200       01/01/2014 13:00 
300       01/01/2014 15:00 
300       01/01/2014 16:00 
100       02/01/2014 08:00 
100       02/01/2014 09:00 
100       03/01/2014 10:00 
Run Code Online (Sandbox Code Playgroud)

我想要一个查询,该查询将对作业进行分组并返回每个组中的第一个和最后一个日期时间。然而,正如您在这里看到的,100 个作业编号有 2 组。我不希望第二组与第一组合并。

相反,我想要这样:

JobNumber   First Weigh         Last Weigh
100         01/01/2014 08:00    01/01/2014 10:00
200         01/01/2014 12:00    01/01/2014 13:00
300         01/01/2014 15:00    01/01/2014 16:00
100         02/01/2014 08:00    03/01/2014 10:00
Run Code Online (Sandbox Code Playgroud)

我已经为此苦苦挣扎了几个小时。任何帮助,将不胜感激。

编辑

日期和时间都只是虚拟随机数据。实际数据一天内有数千次称重。我希望每个作业的第一个和最后一个权重来确定作业的持续时间,以便我可以在时间线上表示持续时间。但我想显示作业 100 两次,表示它已暂停并在 200 和 300 完成后恢复

Joe*_*ell 5

这是我的尝试,使用 row_number() 和分区。我已将其分为几个步骤,希望能够使其易于理解。如果您的表已经有一列包含整数标识符,那么您可以省略第一个 CTE。即使在那之后,您也许可以进一步简化它,但它似乎确实有效。

(编辑以添加一个标志,指示按照评论中的要求具有多个范围的作业。)

declare @sampleData table (JobNumber int, TimeOfWeigh datetime);
insert into @sampleData values
    (100, '01/01/2014 08:00'),
    (100, '01/01/2014 09:00'), 
    (100, '01/01/2014 10:00'),
    (200, '01/01/2014 12:00'),
    (200, '01/01/2014 13:00'),
    (300, '01/01/2014 15:00'),
    (300, '01/01/2014 16:00'),
    (100, '02/01/2014 08:00'),
    (100, '02/01/2014 09:00'),
    (100, '03/01/2014 10:00');

-- The first CTE assigns an ordering to the records according to TimeOfWeigh,
-- producing the row numbers you gave in your example.
with JobsCTE as
(    
    select 
        row_number() over (order by TimeOfWeigh) as RowNumber, 
        JobNumber,
        TimeOfWeigh
    from @sampleData
),

-- The second CTE orders by the RowNumber we created above, but restarts the
-- ordering every time the JobNumber changes. The difference between RowNumber
-- and this new ordering will be constant within each group.
GroupsCTE as
(
    select
        RowNumber - row_number() over (partition by JobNumber order by RowNumber) as GroupNumber,
        JobNumber,
        TimeOfWeigh
    from JobsCTE
),

-- Join by JobNumber alone to determine which jobs appear multiple times.
DuplicatedJobsCTE as
(
    select JobNumber 
    from GroupsCTE 
    group by JobNumber 
    having count(distinct GroupNumber) > 1
)

-- Finally, we use GroupNumber to get the mins and maxes from contiguous ranges.
select
    G.JobNumber,
    min(G.TimeOfWeigh) as [First Weigh],
    max(G.TimeOfWeigh) as [Last Weigh],
    case when D.JobNumber is null then 0 else 1 end as [Multiple Ranges]
from
    GroupsCTE G
    left join DuplicatedJobsCTE D on G.JobNumber = D.JobNumber
group by
    G.JobNumber,
    G.GroupNumber,
    D.JobNumber
order by
    [First Weigh];
Run Code Online (Sandbox Code Playgroud)