MSSQL 2005如何将这些数据分组

时间:2019-01-31 09:56:56

标签: sql-server sql-server-2005 group-by rank row-number

我在SQL SERVER 2005中有一个这样的表

No WorkOrder StartDateTime     EndDateTime       
======================================================
1  WO111111  2019-01-01 07:00  2019-01-01 08:00  
2  WO111111  2019-01-01 08:00  2019-01-01 08:30  
3  WO222222  2019-01-01 08:30  2019-01-01 09:30  
4  WO222222  2019-01-01 09:30  2019-01-01 10:00  
6  WO222222  2019-01-01 10:00  2019-01-01 12:00 
7  WO111111  2019-01-01 12:00  2019-01-01 17:00  

如何获取下表

WorkOrder StartDateTime     EndDateTime
============================================
WO111111  2019-01-01 07:00  2019-01-01 08:30
WO222222  2019-01-01 08:30  2019-01-01 12:00
WO111111  2019-01-01 12:00  2019-01-01 17:00

我尝试了row_number()和rank(),但没有用。

DECLARE @Tmp TABLE (No int, WorkOrder varchar(20), StartDateTime datetime, EndDateTime datetime)
insert into @Tmp values(1,'WO111111','2019-01-01 07:00','2019-01-01 08:00')
insert into @Tmp values(2,'WO111111','2019-01-01 08:00','2019-01-01 08:30')
insert into @Tmp values(3,'WO222222','2019-01-01 08:30','2019-01-01 09:30')
insert into @Tmp values(4,'WO222222','2019-01-01 09:30','2019-01-01 10:00')
insert into @Tmp values(5,'WO222222','2019-01-01 10:00','2019-01-01 12:00')
insert into @Tmp values(6,'WO111111','2019-01-01 12:00','2019-01-01 17:00')
select * from @Tmp;
select g,WorkOrder,min(StartDateTime)StartDateTime,Max(EndDateTime)EndDateTime
From(
  select rank()over(order by WorkOrder)as g,* from @Tmp
)a group by g,WorkOrder

3 个答案:

答案 0 :(得分:0)

您可以通过自连接和SUM窗口功能来摆脱困境。首先通过考虑WorkOrder的顺序来确定No值何时可以分组,然后再用MINMAX分组以粉碎日期间隔。 / p>

;WITH LaggedWorkOrder AS
(
    SELECT
        T1.WorkOrder,
        T1.StartDateTime,
        T1.EndDateTime,
        T1.No,
        WorkOrderChange = CASE 
            WHEN T2.WorkOrder = T1.WorkOrder THEN 0 
            ELSE 1 END
    FROM
        @Tmp AS T1
        LEFT JOIN @Tmp AS T2 ON T1.No - 1 = T2.No
),
WorkOrderGroups AS
(
    SELECT
        L.WorkOrder,
        L.StartDateTime,
        L.EndDateTime,
        L.No,
        WorkOrderGroup = SUM(L.WorkOrderChange) OVER (ORDER BY L.No ASC)
    FROM
        LaggedWorkOrder AS L
)
SELECT
    W.WorkOrder,
    StartDateTime = MIN(W.StartDateTime),
    EndDateTime = MAX(W.EndDateTime)
FROM
    WorkOrderGroups AS W
GROUP BY
    W.WorkOrderGroup,
    W.WorkOrder
ORDER BY
    W.WorkOrderGroup

结果:

WorkOrder   StartDateTime               EndDateTime
WO111111    2019-01-01 07:00:00.000     2019-01-01 08:30:00.000
WO222222    2019-01-01 08:30:00.000     2019-01-01 12:00:00.000
WO111111    2019-01-01 12:00:00.000     2019-01-01 17:00:00.000

中间的CTE结果如下:

滞后工作订单(请参阅每当工作订单更改值时):

WorkOrder   StartDateTime               EndDateTime                 No  WorkOrderChange
WO111111    2019-01-01 07:00:00.000     2019-01-01 08:00:00.000     1   1
WO111111    2019-01-01 08:00:00.000     2019-01-01 08:30:00.000     2   0
WO222222    2019-01-01 08:30:00.000     2019-01-01 09:30:00.000     3   1
WO222222    2019-01-01 09:30:00.000     2019-01-01 10:00:00.000     4   0
WO222222    2019-01-01 10:00:00.000     2019-01-01 12:00:00.000     5   0
WO111111    2019-01-01 12:00:00.000     2019-01-01 17:00:00.000     6   1

WorkOrderGroups (生成MAX / MIN的分组值):

WorkOrder   StartDateTime               EndDateTime                 No  WorkOrderGroup
WO111111    2019-01-01 07:00:00.000     2019-01-01 08:00:00.000     1   1
WO111111    2019-01-01 08:00:00.000     2019-01-01 08:30:00.000     2   1
WO222222    2019-01-01 08:30:00.000     2019-01-01 09:30:00.000     3   2
WO222222    2019-01-01 09:30:00.000     2019-01-01 10:00:00.000     4   2
WO222222    2019-01-01 10:00:00.000     2019-01-01 12:00:00.000     5   2
WO111111    2019-01-01 12:00:00.000     2019-01-01 17:00:00.000     6   3

PD::请考虑升级服务器版本,2005年终止于2016年4月。

答案 1 :(得分:0)

  

现在知道您正在使用SQL Server 2005,您将需要依靠outer apply进行此处要求的任意联接以确定相对的先前记录。

您尚未在此处概述谓词。但是从输出中猜测,您正在寻找每个组的第一个WorkOrder,在这种情况下,这似乎要经过一段时间才能出现一个不同的WorkOrder

下面的方法使用apply通过top 1获取先前的记录,特别是outer apply以确保我们不会丢失第一条记录(将其视为{{1} }。

left join迭代器几乎总是被忽略并且经常被遗忘。但是,当您需要迭代而又没有像键这样的具体连接谓词时,它是一个非常功能强大的工具。我在大表上使用了这种方法来解决“前n个问题”,发现有时它的性能要比内置函数好。

请注意,我已选择apply作为平手。

No

答案 2 :(得分:-1)

使用最小,最大分组来获得预期的输出

SELECT WorkOrder, min(StartDateTime),max(EndDateTime) FROM `tb` group by WorkOrder
  

输出

==============

WorkOrder StartDateTime EndDateTime

WO111111  2019-01-01 07:00  2019-01-01 08:30
WO222222  2019-01-01 08:30  2019-01-01 12:00
WO111111  2019-01-01 12:00  2019-01-01 17:00