Eu tenho uma tabela de dados do sensor. Cada linha possui um id de sensor, um carimbo de data / hora e outros campos. Quero selecionar uma única linha com o carimbo de data / hora mais recente para cada sensor, incluindo alguns dos outros campos.
Pensei que a solução seria agrupar por id de sensor e depois ordenar por max (timestamp) assim:
SELECT sensorID,timestamp,sensorField1,sensorField2
FROM sensorTable
GROUP BY sensorID
ORDER BY max(timestamp);
Isso me dá um erro dizendo que "sensorField1 deve aparecer na cláusula group by ou ser usado em um agregado."
Qual é a forma correta de abordar este problema?
sql
greatest-n-per-group
francamente
fonte
fonte
Respostas:
Para fins de integridade, aqui está outra solução possível:
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;
Muito autoexplicativo, eu acho, mas aqui estão mais informações, se desejar, assim como outros exemplos. É do manual do MySQL, mas a consulta acima funciona com todos os RDBMS (implementando o padrão sql'92).
fonte
Isso pode ser feito de uma maneira relativamente elegante
SELECT DISTINCT
, usando o seguinte:SELECT DISTINCT ON (sensorID) sensorID, timestamp, sensorField1, sensorField2 FROM sensorTable ORDER BY sensorID, timestamp DESC;
O acima funciona para PostgreSQL (mais algumas informações aqui ), mas acho que também outros motores. Caso não seja óbvio, o que isso faz é classificar a tabela por ID do sensor e registro de data e hora (do mais recente para o mais antigo) e, em seguida, retorna a primeira linha (ou seja, o registro de data e hora mais recente) para cada ID de sensor exclusivo.
No meu caso de uso, tenho aproximadamente 10 milhões de leituras de sensores de aproximadamente 1 mil, portanto, tentar juntar a tabela a ela mesma em um filtro baseado em carimbo de data / hora consome muitos recursos; o procedimento acima leva alguns segundos.
fonte
Você pode unir a tabela a ela mesma (na id do sensor) e adicionar
left.timestamp < right.timestamp
como condição de união. Então você escolhe as linhas, onderight.id
estánull
. Voila, você tem a ú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)
Mas observe que isso consumirá muitos recursos se você tiver uma pequena quantidade de ids e muitos valores! Então, eu não recomendaria isso para algum tipo de material de medição, onde cada sensor coleta um valor a cada minuto. No entanto, em um Caso de Uso, em que você precisa controlar as "Revisões" de algo que muda apenas "às vezes", é fácil.
fonte
Você só pode selecionar colunas que estão no grupo ou usadas em uma função agregada. Você pode usar uma junção para fazer isso funcionar
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
fonte
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
fonte
Há uma resposta comum que ainda não vi aqui, que é a função de janela. É uma alternativa à subconsulta correlacionada, se seu banco de dados oferecer suporte.
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;
Eu costumo usar isso mais do que subconsultas correlatas. Sinta-se à vontade para me criticar nos comentários sobre eficácia, não tenho muita certeza de como isso se encaixa nesse aspecto.
fonte
Eu tinha praticamente o mesmo problema e acabei encontrando uma solução diferente que torna esse tipo de problema trivial de consultar.
Eu tenho uma tabela de dados do sensor (dados de 1 minuto de cerca de 30 sensores)
e eu tenho uma tabela de sensores que contém muitas coisas estáticas sobre o sensor, mas os campos relevantes são estes:
O tvLastupdate e o tvLastValue são definidos em um acionador em inserções na tabela SensorReadings. Sempre tenho acesso direto a esses valores, sem precisar fazer consultas caras. Isso desnormaliza ligeiramente. A consulta é trivial:
SELECT idSensor,Description,tvLastUpdate,tvLastValue FROM Sensors
Eu uso esse método para dados que são consultados com frequência. No meu caso, tenho uma tabela de sensores e uma grande tabela de eventos com dados chegando em nível de minuto E dezenas de máquinas estão atualizando painéis e gráficos com esses dados. Com meu cenário de dados, o método de gatilho e cache funciona bem.
fonte