soporta segundo registros por optimizar numero lentas generar fila ejemplos cuantas correlativo contador consultas consecutivo sql sql-server max greatest-n-per-group

segundo - numero de fila sql server



Consulta simple para obtener el valor máximo para cada ID (8)

OK tengo una mesa 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

Esto es todo por el mismo día. Solo 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

Intenté usar MAX () y la agregación se confunde con que Station y OwnerID son diferentes para cada registro. ¿Necesito hacer una ÚNETE?


¿Algo como esto? Únase a su tabla consigo misma y excluya las filas para las que 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 incluiría una fila para cada señal más alta, por lo que podría haber varias filas por id.


En el clásico SQL-92 (que no utiliza las operaciones OLAP utilizadas por Quassnoi), puede usar:

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 marcar; se supone que su tabla es ''t'').

La subconsulta en la cláusula FROM identifica el valor de señal máximo para cada id; 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 potencia de señal y esa potencia es la MAX (), entonces obtendrá varias filas de salida para esa ID.

Probado contra IBM Informix Dynamic Server 11.50.FC3 ejecutándose 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

Nombré la tabla Signal_Info para esta prueba, pero parece que produce la respuesta correcta. Esto solo muestra que hay al menos un DBMS que soporta la notación. Sin embargo, me sorprende un poco que MS SQL Server no lo haga. ¿Qué versión está usando?

Nunca deja de sorprenderme la frecuencia con la que se envían las preguntas de SQL sin nombres de tablas.


Podemos hacerlo usando auto-unirse

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


Usted está haciendo una operación de grupo máximo / mínimo. 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 proveedor) para este problema, la mayoría de los cuales son subóptimos en muchas situaciones. Algunos le darán varias filas cuando más de una fila comparta el mismo valor máximo / mínimo; algunos no lo harán Algunos funcionan bien en mesas con un pequeño número de grupos; otros son más eficientes para un número mayor de grupos con filas más pequeñas por grupo.

Aquí hay una discusión de algunos de los más comunes (sesgados en MySQL pero generalmente aplicables). Personalmente, si sé que no hay máximos múltiples (o que no me importa conseguirlos) a menudo tiendo a adoptar el método de unión nula a la izquierda, que publicaré como nadie más lo ha hecho 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;


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 hay duplicados de MAX(signal) para una ID determinada.

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


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


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


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