【问题标题】:Sqlite insert into with unique names, getting idSqlite 插入具有唯一名称,获取 id
【发布时间】:2010-10-25 02:22:01
【问题描述】:

我有一个要插入数据库的字符串列表。它们必须是独一无二的。当我插入时,我希望他们的 ID(用作另一个表中的外键)所以我使用 last_insert_rowid。我遇到了 2 个问题。

  1. 如果我使用替换,他们的 id (整数主键)更新哪个 打破我的数据库(条目指向 不存在的 ID)
  2. 如果我使用忽略,rowid 不会更新,所以我没有得到正确的 ID

我如何获得他们的 ID?如果我不需要,我不想使用 select 语句来检查并插入字符串(如果它不存在)。我该怎么做?

【问题讨论】:

    标签: sqlite unique identity auto-generate


    【解决方案1】:

    当发生 UNIQUE 约束违规时,REPLACE 算法会在插入或更新当前行之前删除导致约束违规的预先存在的行,并且命令会继续正常执行。这会导致rowid发生变化并产生以下问题

    Y:> **sqlite3 test**  
    SQLite version 3.7.4  
    Enter ".help" for instructions  
    Enter SQL statements terminated with a ";"  
    sqlite> **create table b (c1 integer primary key, c2 text UNIQUE);**  
    sqlite> **insert or replace into b values (null,'test-1');**  
    sqlite> **select last_insert_rowid();**  
    1  
    sqlite> **insert or replace into b values (null,'test-2');**  
    sqlite> **select last_insert_rowid();**  
    2  
    sqlite> **insert or replace into b values (null,'test-1');**  
    sqlite> **select last_insert_rowid();**  
    3  
    sqlite> **select * from b;**  
    2|test-2  
    3|test-1  
    

    变通方法是改变c2列的定义如下

    create table b (c1 integer primary key, c2 text UNIQUE ON CONFLICT IGNORE);
    

    并从插入中删除“或替换”子句;

    那么在插入后进行测试时,您需要执行以下 sql:select last_insert_rowid(), changes();

    sqlite> **create table b (c1 integer primary key, c2 text UNIQUE ON CONFLICT IGNORE);**  
    sqlite> **insert into b values (null,'test-1');**  
    sqlite> **select last_insert_rowid(), changes();**  
    1|1  
    sqlite> **insert into b values (null,'test-2');**  
    sqlite> **select last_insert_rowid(), changes();**  
    2|1  
    sqlite> **insert into b values (null,'test-1');**  
    sqlite> **select last_insert_rowid(), changes();**  
    2|0  
    

    第三次插入后更改的返回值将通知您的应用程序,您需要查找“test-1”的rowid,因为它已经在文件中。当然,如果这是一个多用户系统,您也需要将所有这些都包装在一个事务中。

    【讨论】:

    • insert or replace into b values (1,'test-1'); 我不知道 (1,val) 所以我用 null 代替。如果我尝试insert or replace into b (c2) values(val)insert or replace into b (c2) select val 得到相同的结果,我会得到相同的结果。这是一张图片(为什么我不能从 sqlite-shell 复制/粘贴!)i.imgur.com/2a6IY.png
    • hmm,所以我基本上检查更改,如果它的 1 我使用 rowid,否则我需要一个 select 语句。这听起来很像我下面的回答。好的,这是一个可以接受的解决方案,+1。我将当前答案作为接受,因为我在 mysql 下成功测试了它。
    • 您确实知道“已接受”的答案实际上并没有回答您关于在不需要时消除 select 语句的问题;
    • 恐怕你的回答有帮助,但也没有回答这个问题。 OP 希望避免额外的选择查询来获取 id,您仅在唯一约束 not 失败时提供一种避免这种情况的方法。另见我的回答stackoverflow.com/a/65869514/7015849
    【解决方案2】:

    我目前使用下面的

    insert into tbl(c_name) select 'val' where not exists(select id from tbl where c_name ='val');
    select id from tbl where c_name ='val';
    

    【讨论】:

      【解决方案3】:

      “它们必须是唯一的”是指您确定它们是唯一的,或者如果它们不是,则您想要一个错误的结果?如果您只是使字符串本身成为其表中的键,那么我不明白 1 或 2 可能是一个问题 - 如果出现不需要的重复,您将收到所需的错误,否则会收到正确的 ID。也许您可以通过您正在使用的 SQL 代码的小示例、有问题的表、您正在观察的行为以及您想要的行为来澄清您的问题......?

      已编辑:感谢您的编辑,但我仍然不清楚 SQL 给您带来了什么问题!如果您的表格来自,例如:

      CREATE TABLE Foo(
        theid INTEGER PRIMARY KEY AUTOINCREMENT,
        aword TEXT UNIQUE ABORT
        )
      

      那么任何插入重复单词的尝试都会失败(ABORT 关键字是可选的,因为它是 UNIQUE 的默认值)——这不是你想要说“必须是唯一的”,也就是说,如果不是,那就是错误?

      【讨论】:

      • 我希望 last_insert_rowid 给我文本的 id (PK) 而不是错误。到目前为止,replace 更改了破坏先前条目的 ID,并且错误不会返回 rowid。听起来我确实需要分两步执行此操作?一个 select 语句,如果它不存在则一个 insert 语句
      【解决方案4】:

      您的问题的正确答案是:这不能在 sqlite 中完成。您必须进行额外的选择查询。为 last_insert_rowid 引用 docs

      由于违反约束而失败的 INSERT 不是成功的 INSERT,并且不会更改此例程返回的值。因此,INSERT OR FAIL、INSERT OR IGNORE、INSERT OR ROLLBACK 和 INSERT OR ABORT 在插入失败时不会更改此例程的返回值

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-30
        相关资源
        最近更新 更多