如何选择每个项目具有最大时间戳的行集?

Posted

技术标签:

【中文标题】如何选择每个项目具有最大时间戳的行集?【英文标题】:How can I select the set of rows where each item has the greatest timestamp? 【发布时间】:2015-12-09 01:01:15 【问题描述】:

使用 Sqlite,我想获取具有最大时间戳的行的集合。该表包含项目的属性,即键值对和时间戳。我想为每个属性选择最新的值。

考虑以下简化的架构和数据:

CREATE TABLE Properties (thing VARCHAR,
                         key VARCHAR,
                         value VARCHAR,
                         timestamp INT);
INSERT INTO Properties VALUES ("apple", "color", "red", 0);
INSERT INTO Properties VALUES ("apple", "taste", "sweet", 0);
INSERT INTO Properties VALUES ("apple", "size", "small", 0);
INSERT INTO Properties VALUES ("watermelon", "taste", "sweet", 0);
INSERT INTO Properties VALUES ("watermelon", "size", "large", 0);
INSERT INTO Properties VALUES ("watermelon", "color", "pink", 1);
INSERT INTO Properties VALUES ("watermelon", "color", "green", 0);

我想为 thing="watermelon" 编写一个查询,返回:

taste|sweet
size|large
color|pink

注意有两行key="color",查询返回timestamp 值最大的行。此外,一个属性的最大 timestamp 可能与另一个属性不同。

到目前为止我尝试过的包括:

获取thing="watermelon"的属性集:

SELECT DISTINCT(key) FROM Properties WHERE thing='watermelon';

thing="watermelon" 获取key="color" 的最新值:

SELECT * 
FROM Properties
WHERE thing='watermelon'
  AND key='color'
ORDER BY timestamp DESC
LIMIT 1;

但我不知道如何将两者结合起来。我可能是从命令式编程的角度来解决这个问题的,这就是为什么我会感谢帮助。

【问题讨论】:

【参考方案1】:

在 SQLite 3.7.11 或更高版本中,您可以简单地使用 MAX() 从组中选择一行:

SELECT key, value, MAX(timestamp)
FROM Properties
WHERE thing = 'watermelon'
GROUP BY key;

【讨论】:

SQLite 如何知道选择对应于最大时间戳的value?如果查询是select key, value, max(timestamp), min(timestamp),那么查询会返回哪个value 然后它随机选择这两行之一。 它不会仍然在您的查询中选择一个随机的value 行吗?我不确定sqlite,但这是mysql中的常见错误,因为根据mysql文档,允许引擎在选择不在组中的列时返回一个随机值,但实际上它通常返回与之关联的列最大/最小等,所以人们认为这就是它的工作原理。但是这种行为可能会逐个版本地改变。 ***.com/questions/1752556/… SQLite 保证其他列的值来自与 MIN()/MAX() 匹配的行。 当有MIN()/MAX()时,选择is not arbitrary。【参考方案2】:

调整找到here的查询,我想出了以下内容:

SELECT a.* 
FROM Properties AS a 
INNER JOIN (
  SELECT key, MAX(timestamp) AS max_timestamp 
  FROM Properties 
  WHERE thing='watermelon' 
  GROUP BY key) b 
ON a.key = b.key AND a.timestamp = b.max_timestamp 
WHERE thing='watermelon';

似乎有效,但我对 cme​​ts 这个查询的优点/缺点感兴趣。

【讨论】:

【参考方案3】:

使用HAVING 获得简单易读的解决方案:

SQLFiddleDemo

SELECT *
FROM Properties
WHERE thing = "watermelon"
GROUP BY thing, key
HAVING timestamp = MAX(timestamp)

【讨论】:

投反对票有什么特别的原因吗?如果这个解决方案有什么错误,我会很高兴听到它。

以上是关于如何选择每个项目具有最大时间戳的行集?的主要内容,如果未能解决你的问题,请参考以下文章

如何选择具有当天时间戳的行?

如何为每个键值选择具有最新时间戳的行?

如何编写 SQL 来选择具有每个组的最大值(值)的行?

选择具有最大值的行的 ID

如何从具有最后时间戳的数据框中选择不同的记录

用于从表中选择具有最新时间戳的行的 JOOQ 代码