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

Sql 获取每个ID的最大值的简单查询,sql,sql-server,max,greatest-n-per-group,Sql,Sql Server,Max,Greatest N Per Group,好的,我有一张这样的桌子: 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     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,但聚合会弄糟,因为每个记录的电台和所有者ID都不一样。我需要加入吗?

类似的事情?将表本身连接起来,并排除找到更高信号的行

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可能有多行

WITH q AS
         (
         SELECT  c.*, ROW_NUMBER() OVER (PARTITION BY id ORDER BY signal DESC) rn
         FROM    mytable
         )
SELECT   *
FROM     q
WHERE    rn = 1
这将返回一行,即使给定ID存在重复的MAXsignal


在id上有一个索引,signal将大大改进此查询。

在经典SQL-92中,不使用Quassnoi使用的OLAP操作,则可以使用:

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 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有多个条目具有相同的信号强度,并且该强度为最大值,那么您将获得该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支持这种表示法。然而,我有点惊讶MS SQL Server没有-您使用的是哪个版本


提交SQL问题时没有表名的频率总是让我感到惊讶。

您正在执行分组最大值/最小值操作。这是一个常见的陷阱:感觉应该很容易做到,但在SQL中却不是

对于这个问题,标准ANSI和供应商都有许多方法,其中大多数在许多情况下都是次优的。当多行共享相同的最大/最小值时,有些会给您多行;有些人不会。有些人在小组人数较少的桌子上工作得很好;其他方法对于数量较大的组和每个组的行数较小的组更有效

一些常见的方法是有偏见的,但普遍适用。就我个人而言,如果我知道没有多个最大值,或者我不在乎得到它们,我通常倾向于使用空左自连接方法,我将发布其他人还没有使用过的方法:

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;

我们可以使用self-join

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;
挑选 身份证件 max_信号, 物主 所有者 从…起 从表中选择*,按id顺序按信号描述将超额分配列为最大信号
其中,最大信号=1

是的,如果多个电台的信号相同,它会返回重复的信号。经过编辑,每个信号会有多行,但没有重复。如果你只想从信号最高的人群中随机抽取一行,请使用Quassnoi的答案。是的,我认为这是可行的。我需要检查数据。但非常感谢。易于理解,即使在10年后也很有效,非常感谢!那么复杂性呢?这不是在^2上吗?@thegreekness:是否需要在表别名之间包含显式AS?mytable作为联接选择。。。作为b?你不应该,但是…我刚刚意识到-ON条件也必须指定一个join ON信号。这可能是这一系列中唯一有效的解决方案。但它确实需要一个复合索引id signal。我在FROM子句Error中得到一个语法错误,它指向连接,使用aggregate和jon方法比创建列更好。乐观主义者可以评估的是一个整体:这里的计算列需要先计算,所以这很可能需要一个假脱机,如果你在这个列上有一个你应该做的索引,那么连接的效率会更低。+我知道这不是SQL Server 200的情况,但是有了索引,SQL Server 2005的效率会更高。很高兴知道。我刚刚用13k行和300k行表进行了测试。IO越小越好,适用于更小的表您使用的是哪个版本的SQL Server?使用reading和highersignal别名可以轻松理解查询!非常感谢。

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
SELECT * FROM StatusTable WHERE Signal IN ( SELECT A.maxSignal FROM ( SELECT ID, MAX(Signal) AS maxSignal FROM StatusTable GROUP BY ID ) AS A );