sqlite 如果不存在则插入,否则更新?

8mmmxcuj  于 2023-08-06  发布在  SQLite
关注(0)|答案(9)|浏览(120)

对于经典的“如何插入新记录或更新已存在的记录”,我已经找到了一些“可能”的解决方案,但我无法让它们在SQLite中工作。
我有一个定义如下的表:

CREATE TABLE Book 
ID     INTEGER PRIMARY KEY AUTOINCREMENT,
Name   VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level  INTEGER,
Seen   INTEGER

字符串
我想做的是添加一个具有唯一名称的记录。如果“名称”已存在,我想修改字段。
有人能告诉我怎么做吗?

fzwojiic

fzwojiic1#

看看http://sqlite.org/lang_conflict.html
你想要的是:

insert or replace into Book (ID, Name, TypeID, Level, Seen) values
((select ID from Book where Name = "SearchName"), "SearchName", ...);

字符串
请注意,如果表中已存在行,则插入列表中未包含的任何字段都将设置为NULL。这就是为什么ID列有一个子选择:在替换的情况下,语句会将其设置为NULL,然后分配一个新的ID。
如果您希望在替换情况下保留特定字段值,但在插入情况下将字段设置为NULL,也可以使用这种方法。
例如,假设你不想处理Seen

insert or replace into Book (ID, Name, TypeID, Level, Seen) values (
   (select ID from Book where Name = "SearchName"),
   "SearchName",
    5,
    6,
    (select Seen from Book where Name = "SearchName"));

9gm1akwq

9gm1akwq2#

您应该使用INSERT OR IGNORE命令,然后使用UPDATE命令:在下面的例子中,name是一个主键:

INSERT OR IGNORE INTO my_table (name, age) VALUES ('Karen', 34)
UPDATE my_table SET age = 34 WHERE name='Karen'

字符串
第一个命令将插入记录。如果该记录存在,它将忽略与现有主键冲突所导致的错误。
第二个命令将更新记录(现在肯定存在)

slwdgvem

slwdgvem3#

你需要在表上设置一个约束来触发一个“conflict“,然后通过执行一个replace来解决这个问题:

CREATE TABLE data   (id INTEGER PRIMARY KEY, event_id INTEGER, track_id INTEGER, value REAL);
CREATE UNIQUE INDEX data_idx ON data(event_id, track_id);

字符串
然后,您可以发出:

INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 2, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 5);


“SELECT * FROM data”将为您提供:

2|2|2|3.0
3|1|2|5.0


请注意,data.id是“3”而不是“1”,因为REPLACE执行DELETE和INSERT,而不是UPDATE。这也意味着您必须确保定义了所有必要的列,否则将获得意外的NULL值。

polkgigr

polkgigr4#

INSERT OR REPLACE会将其他字段替换为默认值。

--- sample table ---

CREATE TABLE Book (
  ID     INTEGER PRIMARY KEY AUTOINCREMENT,
  Name   TEXT,
  TypeID INTEGER,
  Level  INTEGER,
  Seen   INTEGER
);

INSERT INTO Book VALUES (1001, 'C++', 10, 10, 0);

个字符

如果要保留其他字段

  • 方法一
sqlite> SELECT * FROM Book;
1001|C++|10|10|0

--- Create record for ID = 1001. If insert failed, just ignore
sqlite> INSERT OR IGNORE INTO Book(ID) VALUES(1001);

--- Set other field value
sqlite> UPDATE Book SET Name='SQLite' WHERE ID=1001;

sqlite> SELECT * FROM Book;
1001|SQLite|10|10|0

  • 方法二

使用UPSERTUPSERT已添加到SQLite版本3.24.0(2018-06-04))

INSERT INTO Book (ID, Name)
  VALUES (1001, 'SQLite')
  ON CONFLICT (ID) DO
  UPDATE SET Name=excluded.Name;


excluded.前缀等于VALUES'SQLite')中的值。

ulmd4ohb

ulmd4ohb5#

首先更新一下。如果affected row count= 0,则插入它。它是最简单的,适用于所有RDBMS

dgjrabp2

dgjrabp26#

Upsert是你想要的。UPSERT语法被添加到SQLite 3.24.0版本(2018-06-04)。

CREATE TABLE phonebook2(
  name TEXT PRIMARY KEY,
  phonenumber TEXT,
  validDate DATE
);

INSERT INTO phonebook2(name,phonenumber,validDate)
  VALUES('Alice','704-555-1212','2018-05-08')
  ON CONFLICT(name) DO UPDATE SET
    phonenumber=excluded.phonenumber,
    validDate=excluded.validDate
  WHERE excluded.validDate>phonebook2.validDate;

字符串
请注意,此时实际的单词“UPSERT”不是upsert语法的一部分。
正确的语法是
INSERT INTO ... ON CONFLICT(...) DO UPDATE SET...
如果你正在执行INSERT INTO SELECT ...,那么你的select至少需要WHERE true来解决解析器关于join语法的标记ON的二义性。
请注意,如果必须替换,INSERT OR REPLACE...将在插入新记录之前删除该记录,如果您有外键级联或其他删除触发器,这可能是不好的。

mfuanj7w

mfuanj7w7#

如果你没有主键,你可以插入如果不存在,然后做一个更新。在使用此之前,表必须至少包含一个条目。

INSERT INTO Test 
   (id, name)
   SELECT 
      101 as id, 
      'Bob' as name
   FROM Test
       WHERE NOT EXISTS(SELECT * FROM Test WHERE id = 101 and name = 'Bob') LIMIT 1;

Update Test SET id='101' WHERE name='Bob';

字符串

mftmpeh8

mftmpeh88#

我相信你想要UPSERT
“INSERT OR REPLACE”(没有附加技巧)会将任何未指定的字段重置为NULL或其他默认值。(INSERT OR REPLACE的这种行为与UPDATE不同;它和INSERT完全一样,因为它实际上就是INSERT;但是,如果您想要的是UPDATE-if-exists,那么您可能想要UPDATE语义,并且会对实际结果感到意外。)
建议的UPSERT实现的技巧基本上是使用INSERT OR REPLACE,但指定所有字段,使用嵌入的SELECT子句检索不想更改的字段的当前值。

vbkedwbf

vbkedwbf9#

我认为值得指出的是,如果您没有彻底了解PRIMARY KEYUNIQUE如何交互,这里可能会出现一些意外行为。
例如,如果您只想在 NAME 字段当前未被占用时插入一条记录,并且如果是,您希望触发一个约束异常来告诉您,那么INSERT OR REPLACE将不会抛出异常,而是通过替换冲突记录(具有相同 NAME 的现有记录)来解决UNIQUE约束本身。Gaspard's在上面的his answer中很好地演示了这一点。
如果你想触发一个约束异常,你必须使用一个INSERT语句,并依靠一个单独的UPDATE命令来更新记录,一旦你知道这个名字没有被使用。

相关问题