【问题标题】:SQLite: Prevent insertion of duplicate rows without failingSQLite:防止插入重复行而不会失败
【发布时间】:2019-12-20 06:35:09
【问题描述】:

我读过the question/answer for preventing duplicate rows in a SQLite table,它建议对必要的列进行约束。但是,据我了解,如果我要插入多行,例如在

insert into tableA
select *
from tableB

其中一个违反了约束,整个插入操作都会失败。

有没有办法避免重复,允许插入不违反约束的行,而不违反约束的行?

我的“天真”方法是根据需要唯一的列在源数据和目标表之间进行内部连接,并从源数据中删除匹配的行,但我想知道是否有办法这样做可以让我在目标表中抛出任意数量的行,而无需添加额外的步骤。

【问题讨论】:

    标签: sqlite primary-key unique-constraint


    【解决方案1】:

    你可以用INSERT OR IGNORE INTO....:

    create table tableA(
      col1 int, 
      col2 text unique
    );
    insert into tableA(col1, col2) values
    (1, 'a'), (2, 'b');
    
    create table tableB(
      col1 int, 
      col2 text unique
    );
    insert into tableB(col1, col2) values
    (1, 'a'), (2, 'b'), (3, 'c');
    
    insert or ignore into tableA(col1, col2) 
    select col1, col2 
    from tableB;
    
    select * from tableA;
    

    请参阅demo
    结果:

    | col1 | col2 |
    | ---- | ---- |
    | 1    | a    |
    | 2    | b    |
    | 3    | c    |
    

    【讨论】:

      【解决方案2】:

      您可以使用INSERT INTO ... SELECT,它使用存在逻辑来检查是否已经存在重复:

      INSERT INTO tableA (col1, col2, col3)
      SELECT col1, col2, col3
      FROM tableB b
      WHERE NOT EXISTS (SELECT 1 FROM tableA a WHERE a.col1 = b.col1 AND a.col2 = b.col2);
      

      这假定“重复”由两个或多个具有相同值的col1col2 记录确定。您可以根据需要调整此逻辑。基本思想是整个选择应该运行,只排除那些你知道会导致约束失败的记录。

      【讨论】:

      • 这是我在帖子中提到的“幼稚”方法,它肯定会起作用,但我想知道是否有一种方法不依赖用户事先检查重复项,即 SQLite 本身保留正确行并丢弃其他行的一种方式。这实际上使约束变得毫无意义,因为它防止了约束存在的错误。我想我的问题是错误处理之一?
      • 也许进一步澄清,我正在以面向对象的编程方式考虑这一点 - 一行可能会产生异常,但您捕获异常并允许它继续处理其他行,如果那样的话说得通。如果这在 SQLite 中实际上是不可能的,那么这是正确的答案,但我想确定一下。
      • 您要么使用我的答案,一次插入一条记录(即每次尝试插入一个事务),要么批量插入,并回滚所有内容,以防出现一个约束违规。据我所知,这些是您的选择。
      • 请注意,您的约束并非无用;它仍然保证没有人可以违反您对数据的独特限制。碰巧它可能会使插入大量数据更具挑战性。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      • 1970-01-01
      • 2010-11-09
      • 1970-01-01
      • 2016-02-19
      • 2012-08-30
      相关资源
      最近更新 更多