我发现了一些经典的“将是”解决方案“我如何插入一个新记录或更新一个如果它已经存在”,但我不能让他们中的任何一个在SQLite中工作。

我有一个定义如下的表:

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

我要做的是添加一个具有唯一名称的记录。如果Name已经存在,我想修改字段。

有人能告诉我怎么做吗?


当前回答

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

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';

其他回答

我相信您需要UPSERT。

“INSERT OR REPLACE”在答案中没有额外的技巧,将重置任何您没有指定为NULL或其他默认值的字段。(INSERT OR REPLACE的这种行为不同于UPDATE;它和INSERT很像,因为它实际上是INSERT;然而,如果你想要的是UPDATE-if-exists,你可能想要的是UPDATE语义,并会对实际结果感到意外。)

建议的UPSERT实现的技巧基本上是使用INSERT OR REPLACE,但指定所有字段,使用嵌入式SELECT子句检索不想更改的字段的当前值。

你需要在表上设置一个约束来触发一个“冲突”,然后通过替换来解决:

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

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

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

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';

看看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"));

你应该使用INSERT或IGNORE命令,后面跟着一个UPDATE命令: 在下面的例子中,name是一个主键。

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

第一个命令将插入记录。如果该记录存在,它将忽略与现有主键冲突引起的错误。

第二个命令将更新记录(现在确实存在)