2009-04-16 51 views
15

好,我有一个表是这样的:简单查询抓住最大价值的每个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对于每个记录不同的食堂了。我需要做一个JOIN吗?

+0

您正在使用哪个版本的SQL Server? – 2009-04-16 15:43:52

回答

15

这样的事情?加入你自己的表格,排除找到更高信号的行。

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

+0

是的,如果信号对于多个电台是相同的,那么这会返回重复。 – 2009-04-16 12:46:20

+0

已编辑,因此您每个信号获得多行,但没有重复。如果您只想从信号最高的那些行中随机选择一行,请使用Quassnoi的答案。 – Andomar 2009-04-16 12:50:54

+0

是的,我认为这是工作。我需要检查数据。但是非常感谢。 – 2009-04-16 13:04:29

1
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)的索引将大大改善此查询。

+0

更好地使用聚合和jon方法比创建一个列。优化器可以作为一个整体进行评估:这里计算的列需要首先计算,所以这可能需要一个假脱机程序 – gbn 2009-04-16 13:29:44

+0

如果您有该列的索引(您应该),则联接效率会降低。 – Quassnoi 2009-04-16 13:33:26

+0

+不适用于SQL Server 200,以防万一 – gbn 2009-04-16 13:33:35

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 
3

在传统的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获得多个输出行。


测试对IBM Informix Dynamic Server的11.50.FC3在Solaris 10上运行:

+ 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问题不表名称被提交给我惊喜。

14

您正在按组进行最大/最小操作。这是一个常见的陷阱:它感觉应该很容易做,但是在SQL中,它更加恶化。

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

Here's a discussion一些常见的(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; 
0

我们可以采用自做加盟

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