У меня есть таблица данных датчиков. В каждой строке есть идентификатор датчика, отметка времени и другие поля. Я хочу выбрать одну строку с последней меткой времени для каждого датчика, включая некоторые другие поля.
Я думал, что решением будет сгруппировать по идентификатору датчика, а затем упорядочить по максимальному (временная метка) следующим образом:
SELECT sensorID,timestamp,sensorField1,sensorField2
FROM sensorTable
GROUP BY sensorID
ORDER BY max(timestamp);
Это дает мне сообщение об ошибке, в котором говорится, что «sensorField1 должен находиться в предложении group by или использоваться в совокупности».
Как правильно подойти к этой проблеме?
sql
greatest-n-per-group
откровенно
источник
источник
Ответы:
Для полноты картины вот еще одно возможное решение:
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;
Я думаю, это довольно самоочевидно, но вот дополнительная информация, если хотите, а также другие примеры. Это из руководства MySQL, но указанный выше запрос работает со всеми СУБД (реализующими стандарт sql'92).
источник
Это можно сделать относительно элегантным способом, используя
SELECT DISTINCT
следующее:SELECT DISTINCT ON (sensorID) sensorID, timestamp, sensorField1, sensorField2 FROM sensorTable ORDER BY sensorID, timestamp DESC;
Вышеупомянутое работает для PostgreSQL (дополнительная информация здесь ), но я думаю, также и для других движков. В случае, если это не очевидно, это сортирует таблицу по идентификатору датчика и метке времени (от самого нового к самому старому), а затем возвращает первую строку (т.е. самую последнюю метку времени) для каждого уникального идентификатора датчика.
В моем случае использования у меня есть ~ 10 млн показаний с ~ 1 тыс. Датчиков, поэтому попытка объединить таблицу сама с собой с помощью фильтра на основе временных меток очень ресурсоемка; вышесказанное занимает пару секунд.
источник
Вы можете присоединиться к таблице с самим собой (по идентификатору датчика) и добавить в
left.timestamp < right.timestamp
качестве условия соединения. Затем вы выбираете строки, гдеright.id
находитсяnull
. Вуаля, у вас есть последняя запись по датчику.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)
Но учтите, что это будет очень ресурсоемко, если у вас мало идентификаторов и много значений! Поэтому я бы не рекомендовал это для каких-то измерений, когда каждый датчик собирает значение каждую минуту. Однако в случае использования, когда вам нужно отслеживать «версии» чего-то, что меняется только «иногда», это просто.
источник
Вы можете выбирать только столбцы, которые входят в группу или используются в агрегатной функции. Вы можете использовать соединение, чтобы заставить это работать
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
источник
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
источник
Есть один общий ответ, который я здесь еще не видел, - это оконная функция. Это альтернатива коррелированному подзапросу, если ваша БД поддерживает его.
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;
На самом деле я использую это больше, чем коррелированные подзапросы. Не стесняйтесь обвинять меня в комментариях по поводу эффективности, я не слишком уверен, как это складывается в этом отношении.
источник
У меня была в основном та же проблема, и в итоге я нашел другое решение, которое делает этот тип проблемы тривиальным для запроса.
У меня есть таблица данных датчиков (данные за 1 минуту примерно с 30 датчиков)
и у меня есть таблица датчиков, в которой много статического материала о датчике, но соответствующие поля следующие:
TvLastupdate и tvLastValue устанавливаются в триггере при вставке в таблицу SensorReadings. У меня всегда есть прямой доступ к этим значениям, без необходимости выполнять какие-либо дорогостоящие запросы. Это немного денормализует. Запрос тривиальный:
SELECT idSensor,Description,tvLastUpdate,tvLastValue FROM Sensors
Я использую этот метод для часто запрашиваемых данных. В моем случае у меня есть таблица датчиков и большая таблица событий, в которой данные поступают на минутном уровне, И десятки машин обновляют информационные панели и графики с этими данными. В моем сценарии данных хорошо работает метод триггера и кеширования.
источник