2009-08-10 13 views
0

更新:1回の出荷時間が常に順番に並んでいないことを示すために1回変更されました。ここ sqlのmax/minクエリとデータ変換

は私の入力

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') 

私はmax(stop)行からそれぞれ出荷min(stop)行と時間からの時間を取る必要があると

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

下回ってほしい出力されますそれぞれ始点/終点に配置します。私はこれは複数のクエリではかなり簡単に行うことができますが、私は単一の選択クエリがこれを行うことができるかどうかを探しています。

ありがとうございました!

答えて

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:clusteredインデックスをshipipment_idおよびstop_seqに作成すると、サブクエリの影響は無視されます。これは、すべての句がsargableでインデックス・シークを実行するためです。 – MyItchyChin

0

は、私はあなたではなく「分」の時間より最初時間、およびシーケンスの最後時間ではなく、「最大」の時間が欲しいと思っで修正アム?

+0

が正しいです。 (すなわち、min(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

共通テーブル式(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"を検索し、残りのクエリはそれらの値を基にして、関連する時刻をテーブル "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とPIVOTを活用する示唆しています。これは乱雑に見えるかもしれませんが、私はそれがうまくいくと思います、そして、それは様々な前提に対してより適応可能です。たとえば、最新の日時の値が、指定された出荷の最大の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は何も役に立たないことに注意してください。各タグには1つの[時間]値しかないので、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

に感謝する。これは、私が探しているものよりも少し複雑です。具体的な必要性と、既にストアドプロシージャにCTEの束があり、それを完全に混乱させたくないという事実があります:-)私はrow_number()パーティションでは...私はその機能をより良く理解するためには、もう少し調べる必要があります。あなたに助けと提案をありがとう! – thomas

関連する問題