Tengo una tabla de datos de sensores. Cada fila tiene una identificación de sensor, una marca de tiempo y otros campos. Quiero seleccionar una sola fila con la última marca de tiempo para cada sensor, incluidos algunos de los otros campos.
Pensé que la solución sería agrupar por ID de sensor y luego ordenar por max (marca de tiempo) así:
SELECT sensorID,timestamp,sensorField1,sensorField2
FROM sensorTable
GROUP BY sensorID
ORDER BY max(timestamp);
Esto me da un error que dice que "sensorField1 debe aparecer en la cláusula group by o usarse en un agregado".
¿Cuál es la forma correcta de abordar este problema?
sql
greatest-n-per-group
francamente
fuente
fuente
Respuestas:
En aras de la integridad, aquí hay otra posible solución:
SELECT sensorID,timestamp,sensorField1,sensorField2 FROM sensorTable s1 WHERE timestamp = (SELECT MAX(timestamp) FROM sensorTable s2 WHERE s1.sensorID = s2.sensorID) ORDER BY sensorID, timestamp;
Creo que es bastante autoexplicativo, pero aquí hay más información si lo desea, así como otros ejemplos. Es del manual de MySQL, pero la consulta anterior funciona con todos los RDBMS (implementando el estándar sql'92).
fuente
Esto se puede hacer de una manera relativamente elegante usando
SELECT DISTINCT
, de la siguiente manera:SELECT DISTINCT ON (sensorID) sensorID, timestamp, sensorField1, sensorField2 FROM sensorTable ORDER BY sensorID, timestamp DESC;
Lo anterior funciona para PostgreSQL (más información aquí ) pero creo que también para otros motores. En caso de que no sea obvio, lo que hace es ordenar la tabla por ID de sensor y marca de tiempo (más reciente a más antiguo), y luego devuelve la primera fila (es decir, la última marca de tiempo) para cada ID de sensor único.
En mi caso de uso, tengo ~ 10M lecturas de ~ 1K sensores, por lo que intentar unir la tabla consigo mismo en un filtro basado en marcas de tiempo requiere muchos recursos; lo anterior toma un par de segundos.
fuente
Puede unirse a la tabla consigo mismo (en la identificación del sensor) y agregar
left.timestamp < right.timestamp
como condición de unión. Luego escoges las filas, donderight.id
estánull
. Listo, tienes la última entrada por sensor.http://sqlfiddle.com/#!9/45147/37
SELECT L.* FROM sensorTable L LEFT JOIN sensorTable R ON L.sensorID = R.sensorID AND L.timestamp < R.timestamp WHERE isnull (R.sensorID)
Pero tenga en cuenta que esto consumirá muchos recursos si tiene una pequeña cantidad de identificadores y muchos valores. Por lo tanto, no recomendaría esto para algún tipo de material de medición, donde cada sensor recopila un valor cada minuto. Sin embargo, en un caso de uso, donde necesita realizar un seguimiento de las "revisiones" de algo que cambia "a veces", es fácil.
fuente
Solo puede seleccionar columnas que están en el grupo o que se usan en una función agregada. Puede usar una combinación para que esto funcione
select s1.* from sensorTable s1 inner join ( SELECT sensorID, max(timestamp) as mts FROM sensorTable GROUP BY sensorID ) s2 on s2.sensorID = s1.sensorID and s1.timestamp = s2.mts
fuente
select * from sensorTable where (sensorID, timestamp) in (select sensorID, max(timestamp) from sensorTable group by sensorID)
.WITH SensorTimes As ( SELECT sensorID, MAX(timestamp) "LastReading" FROM sensorTable GROUP BY sensorID ) SELECT s.sensorID,s.timestamp,s.sensorField1,s.sensorField2 FROM sensorTable s INNER JOIN SensorTimes t on s.sensorID = t.sensorID and s.timestamp = t.LastReading
fuente
Hay una respuesta común que todavía no he visto aquí, que es la función de ventana. Es una alternativa a la subconsulta correlacionada, si su base de datos la admite.
SELECT sensorID,timestamp,sensorField1,sensorField2 FROM ( SELECT sensorID,timestamp,sensorField1,sensorField2 , ROW_NUMBER() OVER( PARTITION BY sensorID ORDER BY timestamp ) AS rn FROM sensorTable s1 WHERE rn = 1 ORDER BY sensorID, timestamp;
En realidad, uso esto más que las subconsultas correlacionadas. Siéntase libre de criticarme en los comentarios sobre efeciance, no estoy muy seguro de cómo se compara en ese sentido.
fuente
Tuve casi el mismo problema y terminé con una solución diferente que hace que este tipo de problema sea trivial de consultar.
Tengo una tabla de datos de sensores (datos de 1 minuto de unos 30 sensores)
y tengo una tabla de sensores que tiene muchas cosas principalmente estáticas sobre el sensor, pero los campos relevantes son estos:
TvLastupdate y tvLastValue se establecen en un disparador en inserciones en la tabla SensorReadings. Siempre tengo acceso directo a estos valores sin necesidad de realizar consultas costosas. Esto se desnormaliza ligeramente. La consulta es trivial:
SELECT idSensor,Description,tvLastUpdate,tvLastValue FROM Sensors
Utilizo este método para los datos que se consultan con frecuencia. En mi caso, tengo una tabla de sensores y una tabla de eventos grande, que tienen datos que ingresan a nivel de minutos Y docenas de máquinas están actualizando tableros y gráficos con esos datos. Con mi escenario de datos, el método de disparo y caché funciona bien.
fuente