SQL 查询以获取每个位置的“最新”值

Posted

技术标签:

【中文标题】SQL 查询以获取每个位置的“最新”值【英文标题】:SQL query to get the "latest" value for each location 【发布时间】:2009-11-23 15:39:08 【问题描述】:

我认为很容易解决的问题现在已经被窃听了很长一段时间了。现在我需要你们的帮助。

在 Informix 中,我有一个像这样的“温度”表:

locId dtg 温度 100 2009-02-25 10:00 15 200 2009-02-25 10:00 20 300 2009-02-25 10:00 24 100 2009-02-25 09:45 13 300 2009-02-25 09:45 16 200 2009-02-25 09:45 18 400 2009-02-25 09:45 12 100 2009-02-25 09:30 11 300 2009-02-25 09:30 14 200 2009-02-25 09:30 15 400 2009-02-25 09:30 10

我正在尝试获取在过去 20 分钟内更新值的每个 locId 的最新温度。

所以我想要上表的结果是(假设我在 2009-02-25 10:10 运行查询):

locId dtg 温度 100 2009-02-25 10:00 15 200 2009-02-25 10:00 20 300 2009-02-25 10:00 24

另一件使事情复杂化的事情是,我希望能够在 locId 上提供一个应该被选中的列表。我的意思是使用类似“...locId IN (100,200,400)...”

我尝试在子查询中使用连接(如 SQL Query to get latest price 中所建议的那样),但我无法让它工作。即使没有额外的“最近 20 分钟内的更新”也不会。

选择 t.* 从温度作为吨 JOIN (select locId, max(dtg) from locId IN (100,200,400) group by locId) as l 关于 l.locId=t.locId 和 l.dtg=t.dtg 其中 locId 在 (100,200,400)

这个查询给了我 SQL 错误,但我找不到错误。 是否有我找不到的错误,或者这种方式在 Informix 中是不可能的。

或者还有其他方法可以走吗?感谢所有帮助。

【问题讨论】:

你能解释一下“找不到错误”是什么意思吗?你的意思是没有错误信息,或者你不知道错误信息的原因?我们可以看到确切的错误消息吗? 【参考方案1】:

可以使用以下语法更正您的 SQL 错误:

SELECT t.*
FROM temperatures AS t
INNER JOIN (
    SELECT locId, MAX(dtg) AS maxdtg 
    FROM temperatures 
    WHERE locId IN (100,200,400)  GROUP BY locId
) AS l 
ON l.locId = t.locId AND maxdtg = t.dtg
WHERE t.locId IN (100,200,400)

编辑:另外,一种适当且更动态的方式来解决这个问题:

SELECT t2.* FROM (
    SELECT locId, MAX(dtg) AS maxdtg 
    FROM temperatures 
    GROUP BY locId
) t1
INNER JOIN (
    SELECT locId, dtg, temp 
    FROM temperatures
) t2 
ON t2.locId = t1.locId 
    AND t2.dtg = t1.maxdtg
WHERE t2.dtg > CURRENT YEAR TO MINUTE - 20 UNITS MINUTE

编辑:正在寻找未来超过 20 分钟的帖子,而不是 20 分钟前的帖子...哎呀!

再次编辑:忘记这是针对 Informix 数据库的...为 where 子句提供 MSSQL 语法。

【讨论】:

DATEADD() 在 Informix 或 SQL 标准中不是标准的; getdate() 也不是。等效表达式是“CURRENT YEAR TO MINUTE - 20 UNITS MINUTE”。【参考方案2】:

您需要在子选择中命名 max(dtg) 列 - 您的查询仅按时间匹配所有行,而不仅仅是最新的。

select t1.locId, t1.temp, time
   from temperatures t1
      inner join ( select t1.locId, t1.temp, max(t1.dtg) as time
                     from temperatures group by t1.locId, t1.temp) as t2
        on t1.locId = t2.locId
           and t1.dtg = t2.time
    where t1.locId in (100,200,400)

您也可以在子选择中添加 where 条件,也可以添加一个条件以仅获取过去 20 分钟内的读数。

编辑:根据评论 - 我输入了错误的连接和其他错误。


一些帮助 - 子查询中对 t1 的引用是错误的。您需要一个额外的表参考 (t3):

select t1.locId, t1.temp, time
   from temperatures t1
        inner join (select t3.locId, t3.temp, max(t3.dtg) as time
                      from temperatures as t3 group by t3.locId, t3.temp) as t2
                        on t1.locId = t2.locId and t1.dtg = t2.time
    where t1.locId in (100,200,400)

这会产生结果:

100    15    2009-02-25 10:00
200    20    2009-02-25 10:00
100    13    2009-02-25 09:45
200    18    2009-02-25 09:45
400    12    2009-02-25 09:45
100    11    2009-02-25 09:30
200    15    2009-02-25 09:30
400    10    2009-02-25 09:30

不幸的是,这不是所需的结果,尽管它越来越接近。部分问题是您不希望 t3.temp 在子选择或其 GROUP BY 子句中。

【讨论】:

连接应该在locidt2.time 另外,第 5 行的列名不明确 locId md5sum 我同意让它更清楚 - 但是我认为子选择中的温度是隐藏的 @Mark - 已测试,失败:消息 209,级别 16,状态 1,第 6 行不明确的列名称“locId”。消息 209,级别 16,状态 1,第 6 行不明确的列名称“locId”。消息 209,级别 16,状态 1,第 6 行不明确的列名称“locId”。消息 209,级别 16,状态 1,第 1 行不明确的列名称“locId”。消息 209,级别 16,状态 1,第 1 行不明确的列名称“temp”。 @Mark - 显然tempt1t2 之间也是模棱两可的。【参考方案3】:

我选择创建一个单行表“RefDateTime”来保存参考时间(2009-02-25 10:10)。还有其他方法可以处理 - 特别是写 `DATETIME(2009-02-25 10:10) YEAR TO MINUTE。

CREATE TABLE temperatures
(
    locId   INTEGER NOT NULL,
    dtg     DATETIME YEAR TO MINUTE NOT NULL,
    temp    INTEGER NOT NULL
);

INSERT INTO Temperatures VALUES(100, '2009-02-25 10:00', 15);
INSERT INTO Temperatures VALUES(200, '2009-02-25 10:00', 20);
INSERT INTO Temperatures VALUES(300, '2009-02-25 10:00', 24);
INSERT INTO Temperatures VALUES(100, '2009-02-25 09:45', 13);
INSERT INTO Temperatures VALUES(300, '2009-02-25 09:45', 16);
INSERT INTO Temperatures VALUES(200, '2009-02-25 09:45', 18);
INSERT INTO Temperatures VALUES(400, '2009-02-25 09:45', 12);
INSERT INTO Temperatures VALUES(100, '2009-02-25 09:30', 11);
INSERT INTO Temperatures VALUES(300, '2009-02-25 09:30', 14);
INSERT INTO Temperatures VALUES(200, '2009-02-25 09:30', 15);
INSERT INTO Temperatures VALUES(400, '2009-02-25 09:30', 10);

CREATE TABLE RefDateTime
(
    reftime DATETIME YEAR TO MINUTE NOT NULL
);
INSERT INTO RefDateTime VALUES('2009-02-25 10:10');

SELECT t1.locID, t1.dtg, t1.temp
  FROM temperatures AS t1 JOIN
    (SELECT t2.locID, MAX(t2.dtg) AS latest
        FROM temperatures AS t2
       WHERE t2.dtg > (SELECT RefTime - 20 UNITS MINUTE FROM RefDateTime)
         AND t2.locID IN (100, 200, 400)
       GROUP BY t2.locID) AS t3 ON t1.locID = t3.locID AND t1.dtg = t3.latest
;

这给出了我认为正确的结果:

100     2009-02-25 10:00      15
200     2009-02-25 10:00      20

当 't2.locID IN (100, 200, 400)' 条件被省略时,它也会显示 locID 为 300(和温度为 24)的行。

【讨论】:

以上是关于SQL 查询以获取每个位置的“最新”值的主要内容,如果未能解决你的问题,请参考以下文章

SQL查询以获取给定键的每个实例的最新行

复杂的 SQL 连接查询 - 获取最新行

SQL查询以逐块获取最新数据

Python sqlite3 SQL查询获取具有最新日期但每个唯一列限制的所有条目

sql查询获取每个id的最新记录

SQL 查询 - 获取每个文档的最新文档版本 URL