好的我有这样一张桌子:
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
这是同一天。我只需要Query来返回每个ID的最大信号:
ID Signal Station OwnerID
111 -120 Home 1
222 -95 Work 1
我尝试使用MAX()和聚合混乱,每个记录的Station和OwnerID都不同。我需要加入吗?
答案 0 :(得分:18)
这样的东西?自己加入你的表,并排除找到更高信号的行。
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可能有多行。
答案 1 :(得分:15)
您正在进行分组最大/最小操作。这是一个常见的陷阱:它感觉像是应该很容易做的事情,但在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;
答案 2 :(得分: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问题的频率永远不会让我感到惊讶。
答案 3 :(得分: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
答案 4 :(得分: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
即使给定MAX(signal)
的{{1}}重复,也会返回一行。
在ID
上建立索引将大大改善此查询。
答案 5 :(得分: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;
答案 6 :(得分: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
答案 7 :(得分:0)
SELECT * FROM StatusTable WHERE Signal IN ( SELECT A.maxSignal FROM ( SELECT ID, MAX(Signal) AS maxSignal FROM StatusTable GROUP BY ID ) AS A );
答案 8 :(得分:0)
选择 ID, max_signal, 所有者, ownerId 来自( 从表中选择*,rank()over(按信号desc按ID顺序划分)作为max_signal ) 其中max_signal = 1;