2009-04-16 3 views
15

OK ich eine Tabelle wie folgt aus:Einfache Frage an Schnappen Max Wert für jede 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 

Das alles für den gleichen Tag ist. Ich brauche nur die Abfrage die max Signal für jede ID zurückzukehren:

ID Signal Station OwnerID 
111 -120  Home  1 
222 -95  Work  1 

Ich habe versucht, MAX() verwenden und die Aggregation vermasselt mit der Station und OwnerID für jeden Datensatz anders zu sein. Muss ich ein JOIN machen?

+0

Welche Version von SQL Server verwenden Sie? –

Antwort

15

So ähnlich? Verbinden Sie Ihre Tabelle mit sich selbst und schließen Sie die Zeilen aus, für die ein höheres Signal gefunden wurde.

Dies würde eine Zeile für jedes höchste Signal auflisten, daher könnten mehrere Zeilen pro ID vorhanden sein

+0

Ja, das bringt Duplikate zurück, wenn das Signal für mehrere Stationen gleich ist. –

+0

Bearbeitet, damit Sie mehrere Zeilen pro Signal erhalten, aber keine Duplikate. Verwenden Sie Quassnois Antwort, wenn Sie nur eine zufällige Zeile von denen mit dem höchsten Signal wollen. – Andomar

+0

Ja, ich denke, das funktioniert. Ich muss die Daten überprüfen. Aber vielen Dank. –

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 

Dies wird eine Zeile zurückgeben, auch wenn es Duplikate von MAX(signal) für einen bestimmten ID sind.

Mit einem Index auf (id, signal) wird diese Abfrage erheblich verbessern.

+0

Besser die aggregate- und jon-Methode als das Erstellen einer Spalte verwenden. Der Optimierer kann als Ganzes auswerten: Die berechnete Spalte muss hier zuerst berechnet werden, so dass mehr als wahrscheinlich eine Spool irgendwo benötigt – gbn

+0

Wenn Sie einen Index für diese Spalte haben (was Sie tun sollten), wird die Verknüpfung weniger effizient sein. – Quassnoi

+0

+ nicht für SQL Server 200 nur für den Fall – gbn

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 
+0

Ich bekomme einen "Syntaxfehler in from clausel" Fehler –

+0

@thegreekness: Müssen Sie eine explizite AS zwischen den Tabellen-Aliase einbeziehen? MYTABLE ALS JOIN (SELECT ...) AS b? Sie sollten nicht, aber ... –

+0

Ich habe gerade erkannt - die ON-Bedingung muss auch ein Join On-Signal angeben. –

3

Im klassischen SQL-92 (nicht die OLAP-Operationen von Quassnoi verwendet verwenden), dann können Sie verwenden:

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, übernimmt Ihre Tabelle ist 't'.)

Die Unterabfrage in der FROM-Klausel identifiziert den maximalen Signalwert für jede ID; Der Join kombiniert diesen mit der entsprechenden Datenzeile aus der Haupttabelle.

Hinweis: Wenn für eine bestimmte ID mehrere Einträge vorhanden sind, die alle die gleiche Signalstärke haben und die Stärke MAX() ist, erhalten Sie mehrere Ausgabezeilen für diese ID.


Getestet gegen IBM Informix Dynamic Server 11.50.FC3 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 den Tisch Signal_Info für diesen Test genannt - aber es scheint, die richtige Antwort zu produzieren. Dies zeigt nur, dass mindestens ein DBMS die Notation unterstützt. Allerdings bin ich 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.

+0

Ich bekomme einen Fehler "Syntax Error in FROM-Klausel" und es zeigt auf den JOIN –

14

Sie arbeiten gruppenweise maximal/minimal. Dies ist eine allgemeine Falle: Es fühlt sich an wie etwas, das leicht zu tun sein sollte, aber in SQL ist es erschwerend nicht.

Es gibt eine Reihe von Ansätzen (sowohl Standard-ANSI- als auch herstellerspezifische) für dieses Problem, von denen die meisten in vielen Situationen nicht optimal sind. Einige geben Ihnen mehrere Zeilen, wenn mehr als eine Zeile denselben maximalen/minimalen Wert hat. manche werden nicht. Einige funktionieren gut auf Tabellen mit einer kleinen Anzahl von Gruppen; Andere sind effizienter für eine größere Anzahl von Gruppen mit kleineren Reihen pro Gruppe.

Here's a discussion von einigen der üblichen (MySQL-voreingenommen aber allgemein anwendbar). Persönlich, wenn ich weiß, dass es keine multiplen Maxima gibt (oder sich nicht darum kümmere, sie zu bekommen), tendiere ich oft zur Null-Link-Selbst-Join-Methode, die ich als niemand sonst noch posten werde:

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

Die Verwendung von "Lesen" und "High-Signal" Aliase macht das Verständnis der Abfrage ein Kinderspiel! Vielen Dank. – Sabuncu

0

Wir tun können, selbst 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; 

Oder Sie können auch die folgende Abfrage

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

Fügen Sie einige Erklärungen hinzu – HaveNoDisplayName

0
 
SELECT * FROM StatusTable 
WHERE Signal IN (
    SELECT A.maxSignal FROM 
    (
     SELECT ID, MAX(Signal) AS maxSignal 
     FROM StatusTable 
     GROUP BY ID 
    ) AS A 
); 
verwenden 0