Domanda

OK Ho una tabella come questa:

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

Questo è tutto per lo stesso giorno. Ho solo bisogno la query per restituire il segnale di massima per ogni ID:

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

Ho provato ad utilizzare MAX () e l'aggregazione scombina con la Stazione e ownerid essere diverso per ogni record. Ho bisogno di fare un JOIN?

È stato utile?

Soluzione

qualcosa di simile? Unire la vostra tavola con sé, ed escludere le righe per le quali è stato rinvenuto un segnale più alto.

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
)

Ciò lista una riga per ogni segnale alto, quindi ci potrebbe essere più righe per id.

Altri suggerimenti

Si sta facendo un massimo operazione di gruppo-saggio / minimo. Questa è una trappola comune. Ci si sente come qualcosa che dovrebbe essere facile da fare, ma in SQL che aggravatingly non è

Ci sono un certo numero di approcci (sia standard ANSI e specifico del fornitore) a questo problema, la maggior parte dei quali sono sub-ottimale in molte situazioni. Alcuni vi darà più righe quando più di una riga condivide lo stesso valore massimo / minimo; altri no. Alcuni funzionano bene su tavoli con un piccolo numero di gruppi; altri sono più efficiente per un numero maggiore di gruppi con piccole righe per gruppo.

Ecco un discussione di alcuni dei più comuni (MySQL polarizzati ma generalmente applicabile). Personalmente, se so che non ci sono maxima multipla (o non si preoccupano di far loro) spesso mi tendo verso il metodo null-sinistra-self-join, che vi posterò come nessun altro ha ancora:

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;

Nel classico SQL-92 (se non utilizzano le operazioni OLAP utilizzati da Quassnoi), quindi è possibile utilizzare:

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;

(sintassi non registrato;. Presuppone che il tavolo è 't')

Il sub-query nella clausola FROM identifica il valore massimo del segnale per ogni id; il join unisce che con la corrispondente riga di dati dalla tabella principale.

. NB: se ci sono diverse voci per uno specifico ID che tutti hanno la stessa forza del segnale e che la forza è il MAX (), allora si otterrà diverse file di output per tale ID


Provato contro IBM Informix Dynamic Server 11.50.FC3 in esecuzione su 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

Ho chiamato la tavola Signal_Info per questo test - ma sembra per produrre la risposta giusta. Questo dimostra solo che ci sia almeno un DBMS che supporti la notazione. Tuttavia, io sono un po 'sorpreso che MS SQL Server non lo fa -? Quale versione stai usando


Non cessa mai di sorprendermi quanto spesso le domande di SQL sono presentato senza nomi di tabella.


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

Questo restituirà una riga anche se ci sono duplicati di MAX(signal) per un dato ID.

Avere un indice su (id, signal) migliorerà notevolmente la query.

Possiamo farlo utilizzando auto unirsi

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;

In alternativa è anche possibile utilizzare la seguente query

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
);

selezionare  id,  max_signal,  proprietario,  ownerid A PARTIRE DAL (   select *, rango () su (partizione per ordine id dal disc segnale) come max_signal da tavolo ) dove max_signal = 1;

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top