Consulta simple para obtener el valor máximo para cada ID
-
09-09-2019 - |
Pregunta
OK tengo una tabla como esta:
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
Todo esto es por el mismo día.Solo necesito que la consulta devuelva la señal máxima para cada ID:
ID Signal Station OwnerID
111 -120 Home 1
222 -95 Work 1
Intenté usar MAX() y la agregación se estropea porque Station y OwnerID son diferentes para cada registro.¿Necesito unirme?
Solución
Algo como esto? Unirse a su mesa con sí mismo, y excluir a las filas de los que se encontró una señal de 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
)
Esta sería una lista de una fila para cada señal más alta, lo que podría haber múltiples filas por ID.
Otros consejos
Usted está haciendo un máximo funcionamiento del grupo sabia / mínimo. Esta es una trampa común:. Se siente como algo que debería ser fácil de hacer, pero en SQL que no es aggravatingly
Hay una serie de enfoques (tanto estándar ANSI y específica del proveedor) a este problema, la mayoría de los cuales son sub-óptimos en muchas situaciones. Algunos le dan varias filas cuando más de una fila comparte el mismo valor máximo / mínimo; otros no. Algunos trabajan bien en tablas con un pequeño número de grupos; otros son más eficiente para un mayor número de grupos con filas más pequeñas por grupo.
He aquí una discusión de algunos de los más comunes (MySQL-polarización negativa de aplicación general). Personalmente, si sabemos que no hay múltiples máximos (o no se preocupan por conseguir ellos) A menudo me inclino por el método nula de izquierda autocombinación, que voy a publicar ya que nadie más ha aún:
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;
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')
El sub-consulta en la cláusula FROM identifica el valor máximo de la señal para cada ID; la unión combina que con la correspondiente fila de datos de la tabla principal.
Nota:. Si hay varias entradas para un ID específico que todos tienen la misma intensidad de señal y que la fuerza es el MAX (), por lo que recibirá varias filas de salida para ese 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
puse el nombre de la tabla Signal_Info para esta prueba - pero parece que para producir la respuesta correcta. Esto sólo muestra que hay al menos un DBMS que soporta la notación. Sin embargo, estoy un poco sorprendido de que MS SQL Server no hace -? Qué versión está usando
Nunca deja de sorprenderme la frecuencia con preguntas SQL se sometió sin nombres de tabla.
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
Esto le devolverá una fila, incluso si no son duplicados de MAX(signal)
para un ID
dado.
Tener un índice en (id, signal)
mejorará en gran medida esta consulta.
Podemos hacerlo usando la autounión.
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 puedes 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;
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 );
seleccione carné de identidad, max_signal, propietario, ID_PROPIETARIO DE ( seleccionar *, rango () sobre (partición por orden Identificación por desc señal) como max_signal de la mesa ) donde max_signal = 1;