【问题标题】:Sqlite3 find changes in row valuesSqlite3 查找行值的变化
【发布时间】:2020-04-18 05:58:46
【问题描述】:

我正在使用 Python 将如下所示的海洋 AIS 数据收集到 sqlite3 数据库中;

|MMSI|TSTAMP|LATITUDE|LONGITUDE|COG|SOG|HEADING|NAVSTAT|IMO|NAME|CALLSIGN|TYPE|A|B|C|D|DRAUGHT|DEST|ETA|MGRS|UNIQUEREF|
636018508|1576547278|36.48892|14.52537|286.0|6.2|284|5|9481960|BRIGHT STAR|D5QA2|79.0|149.0|31.0|9.0|21.0|9.8|DZGHZ|12-19 11:00|33SVA57483828|636018508-1576547278.0
636018508|1576547158|36.48695|14.5334|286.0|12.1|284|0|9481960|BRIGHT STAR|D5QA2|79.0|149.0|31.0|9.0|21.0|9.8|DZGHZ|12-19 11:00|33SVA58203806|636018508-1576547158.0
636018508|1576547098|36.486|14.53742|286.0|12.1|284|0|9481960|BRIGHT STAR|D5QA2|79.0|149.0|31.0|9.0|21.0|9.8|DZGHZ|12-19 11:00|33SVA58563795|636018508-1576547098.0
636018508|1576546858|36.48185|14.55417|284.0|12.2|284|0|9481960|BRIGHT STAR|D5QA2|79.0|149.0|31.0|9.0|21.0|9.8|DZGHZ|12-19 11:00|33SVA60063748|636018508-1576546858.0
636018508|1576545900|36.46573|14.6182|289.0|12.2|288|0|9481960|BRIGHT STAR|D5QA2|79.0|149.0|31.0|9.0|21.0|9.8|DZGHZ|12-19 11:00|33SVA65793567|636018508-1576545900.0

python每分钟下载一次数据,将数据插入pandas的临时表中。为避免重复行,最后一个字段是前两个字段(日期时间纪元和唯一 ID)的组合,它们连接在一起,为每一行提供一个唯一 ID。然后在我的主表中,我设置了一个具有唯一约束的列。

然后使用复制数据;

INSERT OR IGNORE INTO <main table> FROM <temp table>;

我想将所有数据保留在主表中,以便建立一个历史数据库,但是我还需要监控某些字段的变化。例如,在数据 sn-p 中,您可以看到在顶行中,第 7 个字段已从 12.1 更改为 6.2,第 8 个字段已从 0 更改为 5。顶行是最近的更新,因为它具有最新纪元。问题是主数据库将非常大(目前为 49487034 行),我需要在最新数据进入前的 1 分钟内检测所有新行的任何更改。

到目前为止我已经尝试过什么;

GROUP BY unique MMSI ORDER BY TSTAMP DESC LIMIT 2; 

然后使用条件语句检查更改。问题是这样做需要很长时间,因为我们要过滤整个数据库,然后对所有记录进行排序,然后检查更改。

我不是最有经验的程序员,但我会说我需要使用更矢量化的方法,而不是本质上的循环。

我的第二个想法是构建第三个表,该表也从临时表中获取数据,但是它只保存最近的 2 次更新,但是来自数据库 POV 我不确定这将如何影响数据库,因为一个整体,也不确定是否有更快的方法来实现我想要的。

我的最后一个想法是使用触发器,但这肯定只会和我上面的第二个想法一样快吗?

正在寻找有关如何在不到 1 分钟的时间内识别这些变化的任何建议?谢谢。

【问题讨论】:

  • 你为什么要做那个串联的事情,而不是仅仅让前两列成为 PK 或唯一的(在 sqlite 中真的是一样的东西,除非它是一个没有 rowid 的表)?
  • 我不知道我可以使用 2 列创建 PK 或唯一约束,这就是我决定创建唯一引用的原因。你有任何链接来证明你的意思吗?谢谢。
  • tutorialspoint.com/sqlite/sqlite_primary_key.htm 谢谢你,我将修改我的代码以使用它而不是 uniqueRef(更少的存储空间!)。它称为复合键。
  • 就像我看过的许多教程点文章一样,那一篇是完全错误的。 Sqlite 不支持ALTER TABLE 的那种形式。

标签: python-3.x database pandas sqlite triggers


【解决方案1】:

您可以使用lag() 窗口函数(需要 Sqlite 3.25 或更高版本)将当前行的值与上一行的值进行比较,并仅选择不同的值。比如:

WITH cte AS
 (SELECT mmsi, tstamp, sog, navstat
       , lag(sog, 1) OVER previous AS prev_sog
       , lag(navstat, 1) OVER previous AS prev_navstat
  FROM data
  WINDOW previous AS (PARTITION BY mmsi ORDER BY tstamp))
SELECT * FROM cte
WHERE sog <> prev_sog OR navstat <> prev_navstat
ORDER BY mmsi, tstamp;

db-fiddle example

如果您想将其限制为仅包含从最后一分钟开始的时间戳的行,您可以使用 strftime() 添加 where 子句:

WITH cte AS
 (SELECT mmsi, tstamp, sog, navstat
       , lag(sog, 1) OVER previous AS prev_sog
       , lag(navstat, 1) OVER previous AS prev_navstat
  FROM data
  WHERE tstamp >= strftime('%s', 'now', '-1 minute')
  WINDOW previous AS (PARTITION BY mmsi ORDER BY tstamp))
SELECT * FROM cte
WHERE sog <> prev_sog OR navstat <> prev_navstat
ORDER BY mmsi, tstamp;

【讨论】:

  • 如何将结果插入到不同的表中?
猜你喜欢
  • 2020-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多