sql max / min запрос и преобразование данных - PullRequest
0 голосов
/ 11 августа 2009

обновление: изменено один раз, чтобы показать, что время доставки может быть не всегда в последовательном порядке.

вот мой ввод

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) и место в начале / конце соответственно. я знаю, что это можно сделать с несколькими запросами довольно легко, но я смотрю, можно ли это сделать одним запросом выбора.

спасибо!

Ответы [ 6 ]

4 голосов
/ 11 августа 2009

Я думаю, что вы сможете сделать это только с помощью подзапросов.

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, чтобы разделить столбец времени, чтобы получить точный вывод.

1 голос
/ 11 августа 2009

Использовать общее табличное выражение (CTE) - это работает (по крайней мере, в моей тестовой системе 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

CTE SeqMinMax выбирает минимальное и максимальное значения "stop_seq" для каждого "shipment_id", а затем остальная часть запроса строится на этих значениях для извлечения связанных времен из таблицы "test".

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

Марк

0 голосов
/ 11 августа 2009

Я предлагаю вам воспользоваться row_number и PIVOT. Это может выглядеть грязно, но я думаю, что это будет хорошо работать, и это более адаптируется к различным предположениям. Например, он не предполагает, что последнее значение 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 голосов
/ 11 августа 2009
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 голосов
/ 11 августа 2009
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
0 голосов
/ 11 августа 2009

Правильно ли я считаю, что вам нужно время first , а не 'min', и время last в последовательности, а не 'max' время?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...