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 完成后恢复
这是我的尝试,使用 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)