SQLite插入-重复密钥更新时(UPSERT)

SQLite插入-重复密钥更新时(UPSERT),sql,mysql,database,sqlite,upsert,Sql,Mysql,Database,Sqlite,Upsert,MySQL有如下功能: INSERT INTO visits (ip, hits) VALUES ('127.0.0.1', 1) ON DUPLICATE KEY UPDATE hits = hits + 1; 据我所知,SQLite中不存在此功能,我想知道的是,是否有任何方法可以在不执行两个查询的情况下实现相同的效果。此外,如果不可能,您更喜欢什么: 选择+(插入或更新)或 更新(+更新失败时插入) 我更喜欢更新(+如果更新失败则插入)。更少的代码=更少的bug INSERT OR IGN

MySQL有如下功能:

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON DUPLICATE KEY UPDATE hits = hits + 1;
据我所知,SQLite中不存在此功能,我想知道的是,是否有任何方法可以在不执行两个查询的情况下实现相同的效果。此外,如果不可能,您更喜欢什么:

  • 选择+(插入或更新)
  • 更新(+更新失败时插入)
  • 我更喜欢
    更新(+如果更新失败则插入)
    。更少的代码=更少的bug

    INSERT OR IGNORE INTO visits VALUES ($ip, 0);
    UPDATE visits SET hits = hits + 1 WHERE ip LIKE $ip;
    
    这要求“ip”列具有唯一(或主键)约束



    编辑:另一个很好的解决方案:。

    您应该使用memcached,因为它是一个存储单个值(访问次数)的单键(IP地址)。您可以使用原子增量函数来确保没有“竞争”条件


    它比MySQL更快,并且节省了负载,因此MySQL可以专注于其他事情。

    当前的答案仅适用于sqlite或MySQL(取决于您是否使用)。因此,如果您想要跨dbms的兼容性,下面将做

    REPLACE INTO `visits` (ip, value) VALUES ($ip, 0);
    
    ,现在您可以简单地编写以下内容

    INSERT INTO visits (ip, hits)
    VALUES ('127.0.0.1', 1)
    ON CONFLICT(ip) DO UPDATE SET hits = hits + 1;
    

    谢谢@山姆似乎同意你的看法。我也更喜欢这种方法。@Smith我的意思是使用普通的UPDATE和INSERT语句并检查返回值。这没有原子性。如果在其间插入其他进程,则INSERT可能会失败。如果数据没有那么重要,则是的。但是,如果在许多IP访问服务的繁忙站点上使用此服务,则memcached实例可能已满,并导致某些内容被删除。备份memcached内容也会很有趣(如果需要)。@ElliotFoster memcached可以处理与您扔给它的RAM一样多的数据(如果您需要Persistance,也可以使用redis或membase)。如果您每天的访问量超过100万,那么您可能可以为memcache实例提供超过30MB的ram(我认为这是默认值)。然而,就你给它的内存量而言,它当然可以处理比SQLite和MySQL高得多的负载——只是没有任何比较。请不要把我的评论误认为是对memcache的投票,因为我认为它是一个很棒的工具。正如redis一样(我不能代表membase说话,因为我没有使用过它。)然而,memcache/redis并不是最可靠的存储。是的,redis具有持久性,但数据是以一定的间隔(我上次查看)持久化到磁盘的,而memcache则完全没有。就像我说的,如果数据不重要(或者可以很容易地复制),那么memcache和公司就很棒了。原始帖子还询问了sqlite,它与MySQL非常不同,可能意味着它们在其他方面受到限制。您可以配置Redis以尽可能快的速度保存数据(在X秒数或Y次更改时)。只是为了记录,
    REPLACE
    不是一个选项。关于“另一个伟大的解决方案”链接,我也会考虑同一个问题的不同答案:被接受的答案在SQLite(这是我的目标)上起作用。code>REPLACE也可以在SQLite上使用,但在MySQL上,它总是会将计数器重置为0-虽然查询是可移植的,但最终结果会有很大不同。你是对的,我以为OP是在寻找可移植的东西。我意识到“替换到”不适用于所有情况,尤其是需要保留PK的情况,但适用于许多情况。彻底失败而不是丢弃数据是一项功能,而不是一个错误。替换总是先删除行,所以它很混乱。我想知道您是否可以在一个事务中执行多个
    upsert
    ,即,使用Python
    executemany()
    函数?{“SQL逻辑错误或缺少数据库\r\nNAR\”ON\“:语法错误”执行上述命令时,得到exception@jithu您使用的是哪个版本的SQLite?