Sqlite 插入具有唯一名称,获取 id
我有一个要插入数据库的字符串列表。 它们必须是独一无二的。 当我插入时,我想要它们的ID(用作另一个表中的外键),所以我使用last_insert_rowid。 我遇到两个问题。
- 如果我使用替换,他们的ID (整数主键)更新 破坏了我的数据库(条目指向 不存在的 ID)
- 如果我使用忽略,rowid 不会更新,所以我没有获得正确的 ID
我如何获得他们的 ID? 如果我不需要,我不想使用 select 语句来检查并插入字符串(如果它不存在)。 我应该怎么做?
I have a list of strings to insert into a db. They MUST be unique. When i insert i would like their ID (to use as a foreign key in another table) so i use last_insert_rowid. I get 2 problems.
- If i use replace, their id
(INTEGER PRIMARY KEY) updates which
breaks my db (entries point to
nonexistent IDs) - If i use ignore, rowid is not updated so i do not get the correct ID
How do i get their Ids? if i dont need to i wouldnt want to use a select statement to check and insert the string if it doesnt exist . How should i do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当发生
UNIQUE
约束违规时,REPLACE
算法会在插入或更新当前行之前删除导致约束违规的预先存在的行,并且命令继续正常执行。 这会导致rowid
更改并产生以下问题:解决方法是更改
c2
列的定义,如下所示:并删除
或替换
子句;insert
中的那么在
insert
之后进行测试时,需要执行以下sql:select last_insert_rowid(),changes();
第三个
之后changes的返回值insert
将通知您的应用程序,您需要查找"test-1"
的rowid
,因为它已经在文件中。 当然,如果这是一个多用户系统,您也需要将所有这些都包装在一个事务中。When a
UNIQUE
constraint violation occurs, theREPLACE
algorithm deletes pre-existing rows that are causing the constraint violation prior to inserting or updating the current row and the command continues executing normally. This causes therowid
to change and creates the following problem:The work around is to change the definition of the
c2
column as follows:and to remove the
or replace
clause from yourinsert
s;then when test after your
insert
, you will need to execute the following sql:select last_insert_rowid(), changes();
The return value of changes after the 3rd
insert
will be a notification to your application that you will need to lookup therowid
of"test-1"
, since it was already on file. Of course if this is a multi-user system, you will need to wrap all this in a transaction as well.我目前使用以下
I use the below currently
“它们必须是唯一的”,是否意味着您确定它们是唯一的,或者如果它们不是,您希望出现错误? 如果您只是将字符串本身作为其表中的键,那么我不明白 1 或 2 怎么会成为问题——如果出现不需要的重复,您将收到所需的错误,否则将收到正确的 ID。 也许你可以用你正在使用的 SQL 代码的一个小例子、有问题的表、你正在观察的行为以及你想要的行为来澄清你的问题......?
编辑:感谢您的编辑,但我仍然不清楚 SQL 给您带来了什么问题! 如果您的表来自,例如:
那么任何插入重复单词的尝试都将失败(
ABORT
关键字是可选的,因为它是UNIQUE
的默认值) - 不是'鉴于您说“必须是唯一的”,这就是您想要的,即,如果不是,那就是一个错误?By "they MUST be unique", do they mean you are sure that they are, or that you want an error as a result if they aren't? If you just make the string itself a key in its table, then I don't understand how either 1 or 2 could be a problem -- you'll get an error as desired in case of unwanted duplication, otherwise the correct ID. Maybe you can clarify your question with a small example of SQL code you're using, the table in question, what behavior you are observing, and what behavior you'd want instead...?
Edited: thanks for the edit but it's still unclear to me what SQL is giving you what problems! If your table comes from, e.g.:
then any attempt to INSERT a duplicated word will fail (the
ABORT
keyword is optional, as it's the default forUNIQUE
) -- isn't that what you want given that you say the words "MUST be unique", i.e., it's an error if they aren't?您的问题的正确答案是:这不能在 sqlite 中完成。 您必须进行额外的选择查询。 引用last_insert_rowid的文档:
The correct answer to your question is: This cannot be done in sqlite. You have to make an additional select query. Quoting the docs for last_insert_rowid:
在 2022 年遇到同样的问题,但从 SQLite3 版本 3.35.0 (2021-03-12) 开始,我们有 返回。
结合UPSERT,现在可以实现这一目标
,遗憾的是,这仍然是一种解决方法,而不是一个优雅的解决方案...
当发生冲突时,插入变为更新。 这意味着您的更新触发器将会触发,因此您可能需要远离它!
当插入转换为更新时,它需要做一些事情(参见链接)。 然而,我们不想做任何事情,所以我们通过更新
id
本身来执行无操作。然后,
返回 id
给我们我们想要的东西。注意:
on update
将触发。 但如果没有触发器,对数据没有影响on冲突不做任何返回id
不会失败,但不返回id。Having the same problem in 2022, but since SQLite3 version 3.35.0 (2021-03-12), we have RETURNING.
Combined with UPSERT, it is now possible to achieve this
Sadly, this is still a workaround rather than an elegant solution...
On conflict, the insert becomes an update. This means that your update triggers will fire, so you may want to stay away from this!
When the insert is converted into an update, it needs to do something (cf link). However, we don't want to do anything, so we do a no-op by updating
id
with itself.Then,
returning id
gives us the what we want.Notes:
on update
will fire. But without triggers, it has no effect on the dataon conflict do nothing returning id
does not fail, but does not return the id.id
, then this technique does not need any specialization: just copy/pasteon conflict do update set id = id returning id;