2009-08-10 12 views
0

Обновление: одноразовое изменение, чтобы показать, что время доставки не всегда в порядке.sql max/min query and data transform

вот мой вход

create table test 
(
    shipment_id int, 
    stop_seq tinyint, 
    time datetime 
) 

insert into test values (1,1,'2009-8-10 8:00:00') 
insert into test values (1,2,'2009-8-10 9:00:00') 
insert into test values (1,3,'2009-8-10 10:00:00') 
insert into test values (2,1,'2009-8-10 13:00:00') 
insert into test values (2,2,'2009-8-10 14:00:00') 
insert into test values (2,3,'2009-8-10 20:00:00') 
insert into test values (2,4,'2009-8-10 18:00:00') 

вывод, что я хочу ниже

shipment_id start end 
----------- ----- --- 
    1  8:00 10:00 
    2  13:00 18:00 

мне нужно, чтобы занять время от min(stop) строки для каждой партии, и время от max(stop) строки и место в начале/конце соответственно. Я знаю, что это можно сделать с несколькими запросами довольно легко, но я смотрю, может ли один запрос выбора сделать это.

спасибо!

ответ

4

Я думаю, что единственный способ, которым вы сможете это сделать, - это подзапросы.

SELECT shipment_id 
    , (SELECT TOP 1 time 
     FROM test AS [b] 
     WHERE b.shipment_id = a.shipment_id 
     AND b.stop_seq = MIN(a.stop_seq)) AS [start] 
    , (SELECT TOP 1 time 
     FROM test AS [b] 
     WHERE b.shipment_id = a.shipment_id 
     AND b.stop_seq = MAX(a.stop_seq)) AS [end] 
FROM test AS [a] 
GROUP BY shipment_id 

Чтобы получить точный результат, вам понадобится функция DATEPART, чтобы отрубить колонку времени.

+0

времена не всегда могут быть в последовательном порядке ... я забыл показать, что в моем примере ... обновил мой вопрос, чтобы отразить это. – thomas

+0

это работает. Благодарю. я знал, что это можно сделать с несколькими выборами, но пурист во мне искал альтернативы. – thomas

+0

@thomas: Если вы создадите кластерный индекс на shipment_id и stop_seq, влияние выполнения подзапросов будет незначительным, потому что все предложения являются ориентируемыми и будут выполнять поиск индексов. – MyItchyChin

0

Я правильно думать, что вы хотите первого времени, а не «мин» время, и последних раз в последовательности, а не «макс» время?

+0

это правильно. время, связанное с первой остановкой (т. е. мин (stop_seq)), и время, связанное с последней остановкой (то есть max (stop_seq)) – thomas

0
SELECT C.shipment_id, C.start, B2.time AS stop FROM 
( 
    SELECT A.shipment_id, B1.time AS start, A.max_stop_seq FROM 
    (
     SELECT shipment_id, MIN(stop_seq) as min_stop_seq, MAX(stop_seq) as max_stop_seq 
     FROM test 
     GROUP BY shipment_id 
    ) AS A 

    INNER JOIN 

    (
     SELECT shipment_id, stop_seq, time FROM test 
    ) AS B1 

    ON A.shipment_id = B1.shipment_id AND A.min_stop_seq = B1.stop_seq 
) AS C 

INNER JOIN 

(
    SELECT shipment_id, stop_seq, time FROM test 
) AS B2 

ON C.shipment_id = B2.shipment_id AND C.max_stop_seq = B2.stop_seq 
1

Использование Common Table Expression (КТР) - это работает (по крайней мере, на моей тестовой системе SQL Server 2008):

WITH SeqMinMax(SeqID, MinID, MaxID) AS 
(
    SELECT Shipment_ID, MIN(stop_seq), MAX(stop_seq) 
    FROM test 
    GROUP BY Shipment_ID 
) 
SELECT 
    SeqID 'Shipment_ID', 
    (SELECT TIME FROM test 
     WHERE shipment_id = smm.seqid AND stop_seq = smm.minid) 'Start', 
    (SELECT TIME FROM test 
     WHERE shipment_id = smm.seqid AND stop_seq = smm.maxid) 'End' 
FROM seqminmax smm 

SeqMinMax КТР выбирает мин и значения "stop_seq" макс для каждый «shipment_id», а остальная часть запроса затем строит эти значения для извлечения связанных времен из таблицы «test».

CTE поддерживаются на SQL Server 2005 (и стандартная функция SQL: 2003 - нет «изобретения» Microsoft », на самом деле).

Марк

0
select t1.shipment_id, t1.time start, t2.time [end] 
from (
    select shipment_id, min(stop_seq) min, max(stop_seq) max 
    from test 
    group by shipment_id 
) a 
inner join test t1 on a.shipment_id = t1.shipment_id and a.min = t1.stop_seq 
inner join test t2 on a.shipment_id = t2.shipment_id and a.max = t2.stop_seq 
0

Я предлагаю вам воспользоваться row_number и откинуть. Это может показаться беспорядочным, но я думаю, что он будет работать хорошо, и он более приспособлен к различным предположениям. Например, он не предполагает, что последнее значение datetime соответствует наибольшему значению stop_seq для данной партии.

with test_ranked(shipment_id,stop_seq,time,rankup,rankdown) as (
    select 
    shipment_id, stop_seq, time, 
    row_number() over (
     partition by shipment_id 
     order by stop_seq 
    ), 
    row_number() over (
     partition by shipment_id 
     order by stop_seq desc 
    ) 
    from test 
), test_extreme_times(shipment_id,tag,time) as (
    select 
    shipment_id, 'start', time 
    from test_ranked where rankup = 1 
    union all 
    select 
    shipment_id, 'end', time 
    from test_ranked where rankdown = 1 
) 
    select 
    shipment_id, [start], [end] 
    from test_extreme_times 
    pivot (max(time) for tag in ([start],[end])) P 
    order by shipment_id; 
    go 

PIVOT на самом деле не нужен, но это удобно. Однако обратите внимание, что MAX внутри выражения PIVOT ничего полезного не делает. Для каждого тега есть только одно значение [time], поэтому MIN будет работать так же хорошо. Синтаксис требует агрегатной функции в этом положении.

Добавление: Вот адаптация решения CptSkippy, что может быть более эффективным, чем при использовании MIN и MAX, если у вас есть отгрузки таблица:

SELECT shipment_id 
    , (SELECT TOP 1 time 
     FROM test AS [b] 
     WHERE b.shipment_id = a.shipment_id 
     ORDER BY stop_seq ASC) AS [start] 
    , (SELECT TOP 1 time 
     FROM test AS [b] 
     WHERE b.shipment_id = a.shipment_id 
     ORDER BY stop_seq DESC) AS [end] 
FROM shipments_table AS [a]; 
+0

благодаря steve. это выглядит немного сложнее, чем я ищу, учитывая определенную потребность и тот факт, что у меня уже есть куча CTE в моей хранимой процедуре и не хочу полностью ее загромождать :-) Мне нравится row_number() с разделением ... мне нужно исследовать, что еще лучше понять его возможности. спасибо за помощь и предложения! – thomas