SQLite 插入或更新并求和
我有一个表格,用来记录数据的输入和输出:
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 (?, ?, ?);
插入的参数应该已经包含了当前值和新值的总和,特别是xt
和rv
这两个字段。
第二种是把所有操作放在一个查询里,虽然选择数据的过程还是会进行,只不过是在子查询中进行:
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的文档,了解可用的日期和时间函数。