fra*_*ynd 64 sql greatest-n-per-group
我有一张传感器数据表.每行都有一个传感器ID,一个时间戳和其他字段.我想为每个传感器选择一个具有最新时间戳的行,包括一些其他字段.
我认为解决方案是按传感器ID进行分组,然后按max(timestamp)顺序排序,如下所示:
SELECT sensorID,timestamp,sensorField1,sensorField2
FROM sensorTable
GROUP BY sensorID
ORDER BY max(timestamp);
Run Code Online (Sandbox Code Playgroud)
这给了我一个错误,说"sensorField1必须出现在group by子句中或者在聚合中使用".
解决这个问题的正确方法是什么?
fan*_*nts 76
为了完整起见,这是另一种可能的解决方案:
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;
Run Code Online (Sandbox Code Playgroud)
漂亮的自我解释,我认为,但这里的,如果你想更多的信息,以及其他的例子.它来自MySQL手册,但上面的查询适用于每个RDBMS(实现sql'92标准).
小智 36
这可以通过相对优雅的方式使用SELECT DISTINCT
,如下所示:
SELECT DISTINCT ON (sensorID)
sensorID, timestamp, sensorField1, sensorField2
FROM sensorTable
ORDER BY sensorID, timestamp DESC;
Run Code Online (Sandbox Code Playgroud)
以上适用于PostgreSQL(这里有更多信息),但我认为还有其他引擎.如果不明显,它的作用是按传感器ID和时间戳(从最新到最旧)对表进行排序,然后返回每个唯一传感器ID的第一行(即最新时间戳).
在我的用例中,我从~1K传感器读取了大约10M的读数,因此尝试将表连接到基于时间戳的过滤器上是非常耗费资源的; 以上需要几秒钟.
jue*_*n d 18
您只能选择组中的列或在聚合函数中使用的列.您可以使用联接来实现此功能
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
Run Code Online (Sandbox Code Playgroud)
dog*_*ose 17
您可以将表连接到自身(在传感器ID上),并添加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)
Run Code Online (Sandbox Code Playgroud)
但请注意,如果您有少量ID和许多值,这将是非常耗费资源的!因此,我不建议将其用于某种测量材料,其中每个传感器每分钟收集一次值.但是在用例中,您需要跟踪"有时"更改的内容的"修订",这很容易.
我在这里还没有看到一个常见的答案,那就是窗口函数。如果您的数据库支持的话,它是相关子查询的替代方案。
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;
Run Code Online (Sandbox Code Playgroud)
实际上,我比相关子查询更多地使用它。请随意在有关效率的评论中批评我,我不太确定它在这方面的表现如何。
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
Run Code Online (Sandbox Code Playgroud)
八年后,这才得到投票,所以我需要指出这是旧的方法。新方法使用row_number()
加窗函数或APPLY
横向连接。