19

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

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
)

这将为每个最高信号列出一行,因此每个 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 支持该表示法。但是,我有点惊讶 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)给定的 有重复,这也会返回一行ID

启用索引(id, signal)将大大改善此查询。

于 2009-04-16T12:43:07.290 回答
2

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

于 2016-09-04T03:15:17.343 回答
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
从状态表中选择 *
WHERE 信号输入 (
    选择 A.maxSignal FROM
    (
        选择 ID,MAX(信号)作为 maxSignal
        从状态表
        按 ID 分组
    ) 作为一个
);
于 2016-09-04T04:15:59.697 回答
0

select id, max_signal, owner, ownerId FROM ( select * , rank() over(partition by id order by signal desc) as max_signal from table ) where max_signal = 1;

于 2019-05-30T11:25:28.250 回答