【问题标题】:INSERT OR REPLACE + foreign key ON DELETE CASCADE working too goodINSERT OR REPLACE + 外键 ON DELETE CASCADE 工作得很好
【发布时间】:2012-03-26 14:28:20
【问题描述】:

我目前正在尝试创建一个 sqlite 数据库,我可以在其中从另一个 sqlite 数据库(无法附加)导入一个表,并向每列添加一些额外的数据。

由于没有INSERT OR UPDATE 我想出了这个:
我正在考虑将数据拆分为两个表,然后将它们连接起来,这样我就可以将整个导入转储到一个表中,替换所有更改并单独管理额外数据,因为导入时不会更改。

第一个表(我们称之为base_data)看起来像

local_id | remote_id | base_data1 | base_data2 | ...
---------+-----------+------------+------------+----

除了local_id 之外,一切都只是远程数据库的镜像(我可能会添加一个同步时间戳,但现在没关系)。

第二个表看起来很相似,但将remote_id 设置为外键

remote_id | extra_data1 | extra_data2 | ...
----------+-------------+-------------+----

   CREATE TABLE extra_data (
       remote_id INTEGER 
           REFERENCES base_data(remote_id)
           ON DELETE CASCADE ON UPDATE CASCADE
           DEFERRABLE INITIALLY DEFERRED,
       extra_data1 TEXT,
       extra_data2 TEXT,
       /* etc */
   )

现在我的想法是简单地使用 INSERT OR REPLACE INTO base_data ... 值,因为我从中导入的数据库没有同步时间戳或其他任何内容,我必须比较所有内容以找出我必须到 UPDATE 的行/到 INSERT 的行。

但问题就在这里:INSERT OR REPLACE 实际上是一个DELETE,后跟一个INSERT,删除部分会触发外键ON DELETE,我认为我可以通过设置约束DEFERRED 来防止这种情况。如果我将INSERT OR REPLACE 包装在事务中,它也不起作用。尽管语句后存在相同的外键,但它总是删除我的额外数据。

是否可以停止ON DELETE 触发直到INSERT OR REPLACE 完成?也许是一些特殊的交易模式/pragma?

【问题讨论】:

    标签: sqlite


    【解决方案1】:

    如果我将 ON DELETE CASCADE 部分替换为以下触发器,这似乎可行:

    CREATE TRIGGER on_delete_trigger
       AFTER DELETE ON base_data
       BEGIN
           DELETE FROM extra_data WHERE extra_data.remote_id=OLD.remote_id;
       END;
    

    该触发器仅由DELETE 语句触发,到目前为止应该可以解决我的问题。

    (问题中OP提供的答案)

    jmathew 提供的其他信息,引用 documentation

    REPLACE 冲突解决策略删除行以满足约束时,当且仅当启用递归触发器时,删除触发器才会触发。

    【讨论】:

      【解决方案2】:

      假设您在引用表中的主键上只有一个外键关系(正如您在示例中所做的那样),这对我来说被证明是一个相当轻松的解决方案。

      只需禁用外键检查,运行替换查询,然后再次启用外键。

      如果替换查询是在禁用外键时运行的唯一查询,则可以确保不会破坏任何外键。如果您要插入一个新行,则没有任何机会链接到它,如果您要替换一行,则不会删除现有行或查询更改其主键,因此约束仍将成立一旦重新启用外键。

      SQLlite 代码如下所示:

      PRAGMA foreign_keys=OFF;
      INSERT OR REPLACE ...;
      PRAGMA foreign_keys=ON;
      

      【讨论】:

        【解决方案3】:

        这种行为的原因是什么,PostgreSQL 团队有一个explanation

        是的,据我们所知,这是每个 SQL 规范。约束检查可以 推迟到交易结束,但“参考行动”不是 可延期。它们总是在触发语句期间发生。为了 实例 SQL99 将级联删除的结果描述为 引用行立即“标记为删除”,然后

        1. 所有标记为删除的行都被有效删除 在 SQL 语句的末尾,在检查任何 完整性约束。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-10-06
          • 2021-03-29
          • 2012-02-11
          • 2014-02-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多