MSSQL 2005 Как я могу сгруппировать эти данные - PullRequest
0 голосов
/ 31 января 2019

У меня есть такая таблица в 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 голосов
/ 31 января 2019

Теперь, зная, что вы находитесь на SQL Server 2005, вам нужно будет положиться на outer apply, чтобы выполнить произвольное соединение, необходимое здесь для определения относительной предыдущей записи.

Выне обрисовал в общих чертах предикат здесь.Но, исходя из выходных данных, вы ищете первые WorkOrder каждой группы, что в данном случае выглядит как прогон времени, пока не появится другое WorkOrder.

В приведенном ниже подходе используется apply чтобы получить предыдущую запись, используя top 1, в частности outer apply, чтобы гарантировать, что мы не потеряем первую запись (представьте, что это left join).

Итератор apply почти всегда игнорируется и часто забывается.Но это очень мощный инструмент, когда вам нужна итерация без конкретного предиката соединения, такого как ключ.Я использовал этот подход для больших таблиц, чтобы решить «проблему топ-n», обнаруживая, что иногда она работает лучше, чем встроенная.

Обратите внимание, что я выбрал No в качествемой тай-брейк.

CREATE TABLE #WorkOrders (
   No             INT IDENTITY PRIMARY KEY
  ,WorkOrder      VARCHAR(8) NOT NULL
  ,StartDateTime  DATETIME NOT NULL
  ,EndDateTime    DATETIME NOT NULL);

INSERT INTO #WorkOrders (WorkOrder, StartDateTime, EndDateTime)
VALUES  ('WO111111','20190101 07:00','20190101 08:00')
        ,('WO111111','20190101 08:00','20190101 08:30')
        ,('WO111111','20190101 08:30','20190101 09:30')
        ,('WO222222','20190101 08:30','20190101 09:30')
        ,('WO222222','20190101 09:30','20190101 10:00')
        ,('WO222222','20190101 10:00','20190101 12:30')
        ,('WO111111','20190101 12:00','20190101 12:30')

SELECT  wo.WorkOrder
     ,  wo.StartDateTime
     ,  wo.EndDateTime
  FROM  #WorkOrders AS wo 
        OUTER APPLY (
          SELECT  TOP(1)
                  * 
            FROM  #WorkOrders AS wo2 
           WHERE  wo2.StartDateTime < wo.StartDateTime 
           ORDER  BY wo2.StartDateTime DESC, No DESC
        ) AS prev
 WHERE prev.WorkOrder IS NULL
       OR prev.WorkOrder <> wo.WorkOrder

DROP TABLE #WorkOrders;
0 голосов
/ 31 января 2019

Получите ожидаемый результат, используя группу по мин., Макс.

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
0 голосов
/ 31 января 2019

Вы можете обойтись без самостоятельного объединения и оконной функции SUM.Сначала определите, когда значение WorkOrder изменится для возможности группировки, рассмотрев порядок No, затем просто сгруппируйте с помощью MIN и MAX, чтобы разбить интервалы дат.

;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:

LaggedWorkOrder (см. Всякий раз, когда WorkOrder изменяет значение):

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 года.

...