2009-04-16 8 views
15

OK Tengo una tabla como la siguiente:consultas sencillas para agarrar Valor máximo para cada 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 

Esto es todo por el mismo día. Sólo necesito la consulta para devolver la señal máxima para cada ID:

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

He intentado utilizar MAX() y la agregación meta la pata con la Estación y ID_Propietario ser diferente para cada registro. ¿Necesito hacer un JOIN?

+0

¿Qué versión de SQL Server estás usando? –

Respuesta

15

¿Algo como esto? Únase a su mesa consigo mismo, y excluya las filas para las cuales se encontró una señal más alta.

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 
) 

Esto mostraría una fila para cada señal más alta, por lo que podría haber varias filas por identificación.

+0

Sí, esto devuelve duplicados si la señal es la misma para múltiples estaciones. –

+0

Editado para que obtenga varias filas por señal, pero no duplicados. Usa la respuesta de Quassnoi si solo quieres una fila aleatoria entre las que tienen la señal más alta. – Andomar

+0

Sí, creo que esto está funcionando. Necesito verificar los datos. Pero muchas gracias. –

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 

Esto devolverá una fila, incluso si no son duplicados de MAX(signal) para un determinado ID.

Tener un índice en (id, signal) mejorará en gran medida esta consulta.

+0

Es mejor utilizar el método agregado y jon que crear una columna. El optimizador puede evaluar como un todo: la columna calculada aquí necesita calcularse primero, por lo que es más que probable que necesite un spool en algún lugar. – gbn

+0

Si tiene un índice en esta columna (que debería), la combinación será menos eficiente. – Quassnoi

+0

+ no para SQL Server 200 por si acaso – 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

Aparece un error de "error de sintaxis en la cláusula" –

+0

@thegreekness: ¿necesita incluir un AS explícito entre los alias de la tabla? mytable AS a JOIN (SELECCIONAR ...) AS b? No debería, pero ... –

+0

Acabo de darme cuenta - la condición de ENCENDIDO también debe especificar una señal de unión. –

3

En el clásico de SQL-92 (no usar las operaciones OLAP utilizados por Quassnoi), entonces usted puede utilizar:

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; 

(sintaxis sin control; asume su mesa es 't'.)

La subconsulta en la cláusula FROM identifica el valor máximo de la señal para cada identificación; la unión combina eso con la fila de datos correspondiente de la tabla principal.

NB: si hay varias entradas para una ID específica que tienen la misma intensidad de señal y que la intensidad es MAX(), obtendrá varias filas de salida para esa ID.


probado contra IBM Informix Dynamic Server 11.50.FC3 que se ejecutan en 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 

me llamaba la tabla Signal_Info para esta prueba - pero parece que para producir la respuesta correcta. Esto solo muestra que hay al menos un DBMS que admite la notación. Sin embargo, estoy un poco sorprendido de que MS SQL Server no lo haga, ¿qué versión estás usando?


Nunca deja de sorprenderme la frecuencia con preguntas SQL se sometió sin nombres de tabla.

+0

Aparece el error "Error de sintaxis en la cláusula FROM" y apunta al JOIN –

14

Está realizando una operación máxima/mínima en grupo. Esta es una trampa común: se siente como algo que debería ser fácil de hacer, pero en SQL no lo es.

Existen varios enfoques (tanto ANSI estándar como específicos del fabricante) para este problema, la mayoría de los cuales no son óptimos en muchas situaciones. Algunos le darán múltiples filas cuando más de una fila comparte el mismo valor máximo/mínimo; algunos no lo harán. Algunos funcionan bien en tablas con un pequeño número de grupos; otros son más eficientes para un mayor número de grupos con filas más pequeñas por grupo.

Here's a discussion de algunos de los comunes (MySQL-parcial pero generalmente aplicable). Personalmente, si sé que no hay máximos múltiples (o no me importa obtenerlos), a menudo me inclino por el método null-left-self-join, que publicaré como nadie más lo ha hecho todavía:

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

¡El uso de alias de "lectura" y "señal más alta" hace que la comprensión de la consulta sea muy fácil! Gracias. – Sabuncu

0

podemos hacer uso de uno mismo se unen

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; 

O también se puede utilizar la siguiente consulta

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

Añadir un explana – 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 
); 
Cuestiones relacionadas