2009-08-10 60 views
0

更新:更改一次以顯示每批貨物的時間可能不總是按順序排列。sql最大/最小查詢和數據轉換

這裏是我的輸入

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 

我需要從max(stop)排走的時候從min(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 2009-08-10 20:22:54

+0

這個工作。謝謝。我知道這可以用多個選擇來完成,但我的純粹主義者正在尋找替代品。 – thomas 2009-08-10 20:43:48

+0

@thomas:如果您在shipment_id和stop_seq上創建聚集索引,那麼執行子查詢的影響可以忽略不計,因爲所有子句都是可選的,並且會執行索引查找。 – MyItchyChin 2009-08-10 21:19:49

0

難道我的思維糾正你想要的第一時間,而不是在「分鐘」時間,最後的時間序列,而不是「最大」時間?

+0

這是正確的。與第一站相關的時間(即min(stop_seq))以及與最後一站相關的時間(即max(stop_seq)) – thomas 2009-08-10 20:40:52

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

使用公用表表達式(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 

SeqMinMax CTE選擇最小值和最大值 「stop_seq」 值每個「shipment_id」,然後查詢的其餘部分建立在這些值上以從表「檢索」中檢索關聯的時間。

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和樞紐的優勢。這可能看起來很亂,但我認爲它會表現良好,並且更適應各種假設。例如,它不假定最新的日期時間值對應給定貨件的最大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並不是真的需要,但它很方便。但是,請注意PIVOT表達式中的MAX沒有任何用處。每個標籤只有一個[時間]值,因此MIN也會起作用。該語法在這個位置需要一個聚合函數。

附錄:這裏的,如果你有一個出貨量桌子,其可以比使用MIN和MAX更有效CptSkippy的解決方案的適應性:

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 2009-08-11 02:10:36