简单的查询来获取每个ID的最大值

好的,我有一张这样的桌子:

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是不同的每个logging。 我需要join吗?

像这样的东西? join你自己的表格,排除find更高信号的行。

 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 ) 

这将为每个最高信号列出一行,所以每个ID可能有多行。

您正在按组进行最大/最小操作。 这是一个常见的陷阱:感觉应该很容易做,但是在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; 

在经典的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进行testing:

 + 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 

我为这个testing命名了Signal_Info表,但它似乎产生了正确的答案。 这只显示至less有一个支持符号的DBMS。 但是,我有点惊讶,MS SQL Server不 – 你使用的是哪个版本?


从来没有停止惊讶我多less提交没有表名称的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 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 

这将返回一行,即使有一个给定的IDMAX(signal)重复。

(id, signal)上的索引将大大改善此查询。

 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 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 * FROM StatusTable
 WHERE信号IN(
     SELECT A.maxSignal FROM
     (
         SELECT ID,MAX(Signal)AS maxSignal
        从StatusTable
         GROUP BY ID
     ) 作为一个
 );