SQLite 插入或更新并求和

0 投票
2 回答
1936 浏览
提问于 2025-04-18 13:42

我有一个表格,用来记录数据的输入和输出:

CREATE TABLE io(iodate DATE, xt INTEGER, rv INTEGER)

这个表格的目的是按日期存储总共传输的数据量。

为了更新这个表格,我使用了一些查询语句(混合了伪代码和SQL):

SELECT * FROM io WHERE iodate=<today>
if no result:
   INSERT INTO io(iodate, xt, rv) VALUES (...)
else:
   UPDATE io SET rv+=<new_rv> xt+=<new_xt> WHERE iodate=<today>

我觉得还有更方便的方法可以做到这一点。有没有什么好主意?

2 个回答

0

我很遗憾,Python的sqlite3里没有你想要的那种快捷方式。你可以在这里查看sqlite3的说明 这里

我建议你可以这样写代码。(这和你使用伪代码是一样的。)

...
def findData():
    SELECT * FROM io WHERE iodate=<today>
def updateData():
    update operation
def insertData():
    insert operation
[updateData() if findData() else insertData()]
...

因为更新、查找和插入是处理数据库时最常用的操作,把它们放在一个函数里会是个不错的解决办法。

3

假设你在iodate这一列上设置了主键,你可以使用INSERT OR REPLACE,就像@Martijn_Pieters说的那样,但你可以有两种方法:

第一种是先查询当前的数据,就像你已经在做的那样,然后再“插入或替换”:

SELECT * FROM io WHERE iodate = ?;
...
INSERT OR REPLACE INTO io VALUES (?, ?, ?);

插入的参数应该已经包含了当前值和新值的总和,特别是xtrv这两个字段。

第二种是把所有操作放在一个查询里,虽然选择数据的过程还是会进行,只不过是在子查询中进行:

INSERT OR REPLACE INTO io
                select iodate, xt + ?, rv + ? from (
                       SELECT iodate, xt, rv
                         FROM io
                        WHERE iodate = ?
                        union all
                       select ? as iodate, 0 as xt, 0 as rv
                ) limit 1;

第二种方法的主要缺点是你需要重复写iodate两次,所以参数的顺序应该是:<new_xt>, <new_rv>, <iodate>, <iodate>,不过这并不会影响性能。

好处是无论这一行数据是否已经在表中,它始终只需要一个查询。

至于哪种方法更快,很难说。你需要自己去测量一下。

你也可以考虑使用SQLite的日期和时间函数,这样就不用每次都自己传iodate。我猜你的应用程序总是会传递当前的iodate数据,在这种情况下,你可以使用now()函数来代替iodate,或者使用其他相关的函数,以便它符合你的日期格式。可以查看SQLite的文档,了解可用的日期和时间函数。

撰写回答