Einfache Frage an Schnappen Max Wert für jede ID
-
09-09-2019 - |
Frage
OK Ich habe eine Tabelle wie folgt aus:
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
Das ist alles für den gleichen Tag. Ich brauche nur die Abfrage den max Signal für jede ID zurück:
ID Signal Station OwnerID
111 -120 Home 1
222 -95 Work 1
Ich habe versucht, MAX () verwendet und die Aggregation vermasselt mit der Station und OwnerID für jeden Datensatz anders zu sein. Brauche ich einen JOIN?
zu tunLösung
So etwas wie das? Verbinden Sie Ihre Tabelle mit sich selbst, und schließen Sie die Zeilen, für die ein höheres Signal gefunden wurde.
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
)
Dies würde für jedes höchstes Signal eine Zeile Liste, so dass es möglicherweise mehr Zeilen pro-ID sein.
Andere Tipps
Sie machen einen gruppenweise Maximum / Minimum-Betrieb. Dies ist eine gemeinsame Falle:. Es fühlt sich an wie etwas, das einfach zu tun sein sollte, aber in SQL ist es aggravatingly nicht
Es gibt eine Reihe von Ansätzen (sowohl Standard ANSI und herstellerspezifisch) für dieses Problem, die meisten davon in vielen Situationen suboptimal sind. Einige werden Sie mehrere Zeilen geben, wenn mehr als eine Zeile die gleiche Maximum / Minimum-Wert teilt; manche nicht. Einige arbeiten auch auf den Tischen mit einer kleinen Anzahl von Gruppen; andere sind effizienter für eine größere Anzahl von Gruppen mit kleineren Zeilen pro Gruppe.
Hier ist eine Diskussion einige der allgemeinsten (MySQL-voreingenommen, sondern allgemein anwendbar). Persönlich, wenn ich weiß, gibt es keine mehrere Maxima (oder kümmern sich nicht um sie bekommen) Ich neige dazu, oft in Richtung Null-links-Self-Join-Methode, die ich als niemand veröffentlichen werde sonst noch:
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;
In der klassischen SQL-92 (nicht die OLAP-Operationen von Quassnoi verwendet verwenden), dann können Sie:
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;
(Ungeprüft Syntax;. Nimmt an dem Tisch ist 't')
Die Unterabfrage in der FROM-Klausel gibt den maximalen Signalwert für jede id; die Verbindung kombiniert, die mit der entsprechenden Datenzeile von der Haupttabelle.
. NB: wenn es mehr Einträge für eine bestimmte ID, die alle die gleiche Signalstärke haben und dass Stärke ist der MAX (), dann werden Sie für diese ID mehrere Ausgabezeilen erhalten
Getestet gegen IBM Informix Dynamic Server 11.50.FC3 läuft auf 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
Ich nannte die Tabelle Signal_Info für diesen Test - aber es scheint, die richtige Antwort zu produzieren. Dies zeigt nur, dass es mindestens ein DBMS ist, die die Notation unterstützt. Aber ich bin ein wenig überrascht, dass MS SQL Server nicht - welche Version verwenden Sie
Es hört nie auf, mich zu überraschen, wie oft SQL Fragen ohne Tabellennamen vorgelegt werden.
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
Dies wird eine Zeile zurückgeben, auch wenn es Duplikate von MAX(signal)
für einen bestimmten ID
sind.
einen Index für (id, signal)
Having wird diese Abfrage erheblich verbessern.
Wir können selbst tun mit beitreten
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;
Sie können aber auch die folgende Abfrage verwenden
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 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 * FROM StatusTable WHERE Signal IN ( SELECT A.maxSignal FROM ( SELECT ID, MAX(Signal) AS maxSignal FROM StatusTable GROUP BY ID ) AS A );
wählen Ich würde, max_signal, Inhaber, ownerId VON ( select *, Rang () über (Partition-ID, um durch das Signal ab) als max_signal aus der Tabelle ) wo max_signal = 1;