単純なクエリはIDごとに最大値を取得するには
-
09-09-2019 - |
質問
OK私はこのようなテーブルを持っています
ID Signal Station OwnerID
111 -120 Home 1
111 -130 Car 1
111 -135 Work 2
222 -98 Home 2
222 -95 Work 1
222 -103 Work 2
これは、同じ日のためにすべてです。私はIDごとに最大信号を返すようにクエリを必要とします:
ID Signal Station OwnerID
111 -120 Home 1
222 -95 Work 1
私はMAXを使用してみました()と凝集が駅やOWNERIDがレコードごとに異なることと台無し。私はJOINを行う必要がありますか?
解決
このような何か?自身とあなたのテーブルに参加し、より高い信号が見つかったために行を除外します。
select cur.id, cur.signal, cur.station, cur.ownerid
from yourtable cur
where not exists (
select *
from yourtable high
where high.id = cur.id
and high.signal > cur.signal
)
これは、それぞれの最も高い信号に対して1つの行をリストすることになるので、IDごとに複数の行がある可能性があります。
他のヒント
あなたは、グループごとの最大/最小操作を行っています。これは一般的なトラップである:それを行うのは簡単なはずの何かのように感じますが、SQLでそれがaggravatinglyではありません。
。のアプローチの数(標準ANSIおよびベンダー固有の両方)は、多くの状況で次善であるほとんどが、この問題にあります。複数の行が同じ最大/最小値を共有する場合、いくつかはあなたに複数の行を提供します。一部はしません。一部は少数のグループを持つテーブルの上にうまく動作します。他のものは、グループごとに小さい行のグループの多数のために、より効率的である。
ここでは一般的なもの(MySQLのバイアスされたが、一般的に適用)のいくつかの議論のです。
SELECT reading.ID, reading.Signal, reading.Station, reading.OwnerID
FROM readings AS reading
LEFT JOIN readings AS highersignal
ON highersignal.ID=reading.ID AND highersignal.Signal>reading.Signal
WHERE highersignal.ID IS NULL;
には、古典的なSQL-92(Quassnoiで使用されるOLAP操作を使用していない)、その後、あなたが使用することができます:
SELECT g.ID, g.MaxSignal, t.Station, t.OwnerID
FROM (SELECT id, MAX(Signal) AS MaxSignal
FROM t
GROUP BY id) AS g
JOIN t ON g.id = t.id AND g.MaxSignal = t.Signal;
(未確認の構文、あなたのテーブルには 'T' である前提としています。)
FROM句のサブクエリは、各IDの最大信号値を識別する。参加メインテーブルから対応するデータ列とすることを組み合わせたものである。
NB:すべてが同じ信号強度を持っており、その強さはMAX(ある特定のIDのためのいくつかのエントリ)がある場合は、そのIDに対して複数の出力行を取得します。
。 <時間>のSolaris 10上で実行されているIBMのInformix Dynamic Serverの11.50.FC3に対してテスト
+ CREATE TEMP TABLE signal_info
(
id INTEGER NOT NULL,
signal INTEGER NOT NULL,
station CHAR(5) NOT NULL,
ownerid INTEGER NOT NULL
);
+ INSERT INTO signal_info VALUES(111, -120, 'Home', 1);
+ INSERT INTO signal_info VALUES(111, -130, 'Car' , 1);
+ INSERT INTO signal_info VALUES(111, -135, 'Work', 2);
+ INSERT INTO signal_info VALUES(222, -98 , 'Home', 2);
+ INSERT INTO signal_info VALUES(222, -95 , 'Work', 1);
+ INSERT INTO signal_info VALUES(222, -103, 'Work', 2);
+ SELECT g.ID, g.MaxSignal, t.Station, t.OwnerID
FROM (SELECT id, MAX(Signal) AS MaxSignal
FROM signal_info
GROUP BY id) AS g
JOIN signal_info AS t ON g.id = t.id AND g.MaxSignal = t.Signal;
111 -120 Home 1
222 -95 Work 1
私はこのテスト用のテーブルSignal_Infoという名前 - 正しい答えを生成するようです。 これはのみの表記をサポートする、少なくとも1つのDBMSがあることを示しています。どのバージョンを使用している
- ?しかし、私は、MS SQL Serverがないことに少し驚いています <時間>はそれはテーブル名なしで提出される頻度をSQLの質問に私を驚かを停止することはありません。の
with tab(id, sig, sta, oid) as
(
select 111 as id, -120 as signal, 'Home' as station, 1 as ownerId union all
select 111, -130, 'Car', 1 union all
select 111, -135, 'Work', 2 union all
select 222, -98, 'Home', 2 union all
select 222, -95, 'Work', 1 union all
select 222, -103, 'Work', 2
) ,
tabG(id, maxS) as
(
select id, max(sig) as sig from tab group by id
)
select g.*, p.* from tabG g
cross apply ( select top(1) * from tab t where t.id=g.id order by t.sig desc ) p
WITH q AS
(
SELECT c.*, ROW_NUMBER() OVER (PARTITION BY id ORDER BY signal DESC) rn
FROM mytable
)
SELECT *
FROM q
WHERE rn = 1
これは、所与のMAX(signal)
ためID
の重複がある場合でも、一つの行を戻します。
(id, signal)
にインデックスを持つことは非常にこのクエリを改善します。
私たちは自己を使用して行うことができます参加
SELECT T1.ID,T1.Signal,T2.Station,T2.OwnerID
FROM (select ID,max(Signal) as Signal from mytable group by ID) T1
LEFT JOIN mytable T2
ON T1.ID=T2.ID and T1.Signal=T2.Signal;
それとも、また次のクエリを使用することができます。
SELECT t0.ID,t0.Signal,t0.Station,t0.OwnerID
FROM mytable t0
LEFT JOIN mytable t1 ON t0.ID=t1.ID AND t1.Signal>t0.Signal
WHERE t1.ID IS NULL;
select a.id, b.signal, a.station, a.owner from
mytable a
join
(SELECT ID, MAX(Signal) as Signal FROM mytable GROUP BY ID) b
on a.id = b.id AND a.Signal = b.Signal
SELECT * FROM StatusTable WHERE Signal IN ( SELECT A.maxSignal FROM ( SELECT ID, MAX(Signal) AS maxSignal FROM StatusTable GROUP BY ID ) AS A );
を選択 ID、 max_signal、 オーナー、 OWNERID FROM( *テーブルからmax_signalとして()(信号DESCによってID順によるパーティション)上のランクを選択 ) ここmax_signal = 1;