19

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()を使用してみましたが、レコードごとにStationとOwnerIDが異なるため、集計が混乱します。参加する必要がありますか?

4

9 に答える 9

20

このようなもの?テーブルをそれ自体と結合し、より高いシグナルが見つかった行を除外します。

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 ごとに複数の行が存在する可能性があります。

于 2009-04-16T12:37:09.770 に答える
16

グループごとの最大/最小操作を実行しています。これは一般的な罠です。簡単にできるはずのように感じますが、SQLではそうではありません。

この問題にはいくつかのアプローチ(標準のANSIとベンダー固有の両方)があり、そのほとんどは多くの状況で最適ではありません。複数の行が同じ最大値/最小値を共有する場合、複数の行が表示されるものもあります。一部はしません。グループの数が少ないテーブルでうまく機能するものもあります。他のものは、グループあたりの行数が少ない多数のグループに対してより効率的です。

ここでは、いくつかの一般的なものについて説明します(MySQLに偏っていますが、一般的に適用可能です)。個人的には、複数の最大値がないことがわかっている場合(またはそれらを取得することを気にしない場合)、null-left-self-joinメソッドを使用する傾向があります。これは、他の誰もまだ行っていないため、投稿します。

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;
于 2009-04-16T16:15:20.313 に答える
4

従来の 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 の最大シグナル値を識別します。結合は、それをメイン テーブルの対応するデータ行と結合します。

注意: 特定の ID に対して複数のエントリがあり、すべてが同じ信号強度を持ち、その強度が MAX() である場合、その 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 という名前を付けましたが、正しい答えが得られたようです。これは、表記法をサポートする DBMS が少なくとも 1 つあることを示しているだけです。しかし、MS SQL Server がそうではないことに少し驚いています。どのバージョンを使用していますか?


テーブル名なしで SQL の質問が送信される頻度に驚かされます。

于 2009-04-16T12:55:36.700 に答える
2
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)これは、特定の の重複がある場合でも、1 つの行を返しIDます。

インデックスをオンに(id, signal)すると、このクエリが大幅に改善されます。

于 2009-04-16T12:43:07.290 に答える
1

自己結合を使用して実行できます

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;
于 2015-10-28T11:28:25.743 に答える
0
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 
于 2009-04-16T12:52:09.780 に答える
0
SELECT * FROM ステータステーブル
WHERE シグナル IN (
    A.maxSignal FROM を選択
    (
        SELECT ID、MAX(シグナル) AS maxSignal
        FROM StatusTable
        IDでグループ化
    ) として
);
于 2016-09-04T04:15:59.697 に答える
0

select id, max_signal, owner, ownerId FROM ( select * , rank() over(ID オーダーによるパーティション、シグナル desc によるパーティション) as max_signal from table ) where max_signal = 1;

于 2019-05-30T11:25:28.250 に答える