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

我发现了一些经典的“如何插入新logging或更新logging”的解决scheme,但是我不能让它们中的任何一个在SQLite中工作。

我有一个表格定义如下:

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

我想要做的是添加一个独特的名字的logging。 如果名称已经存在,我想修改这些字段。

有人可以告诉我该怎么做吗?

看看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列的子select:在replace的情况下,语句将其设置为NULL,然后将分配一个新的ID。

如果您希望单独保留特定字段值(如果replace案例中的行),但在插入案例中将字段设置为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")); 

您需要在表上设置一个约束来触发一个“ 冲突 ”,然后通过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值。

您应该使用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' 

第一个命令将插入logging。 如果logging存在,则会忽略与现有主键冲突所导致的错误。

第二个命令将更新logging(现在肯定存在)

首先更新它。 如果受影响的行数 = 0,则插入它。 它是最容易和适合所有RDBMS的

INSERT OR REPLACE会将其他字段( TypeIDLevel )replace为默认值。

 INSERT OR REPLACE INTO book(id, name) VALUES(1001, 'Programming') 

我正在使用这个

 INSERT OR IGNORE INTO book(id) VALUES(1001); UPDATE book SET name = 'Programming' WHERE id = 1001; 

你也可以使用

 INSERT OR REPLACE INTO book (id, name) VALUES (1001, 'Programming', (SELECT typeid FROM book WHERE id = 1001), (SELECT level FROM book WHERE id = 1001), ) 

但我觉得第一种方法更容易阅读

如果您没有主键,则可以插入(如果不存在),然后执行更新。 在使用此表之前,表格必须至less包含一个条目。

 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 。

“插入或replace”没有额外的诡计,答案将重置您没有指定为NULL或其他默认值的任何领域。 (INSERT OR REPLACE的这种行为与UPDATE不同,它与INSERT完全相同,因为它实际上是INSERT;但是如果你想要的是UPDATE-if-exists,你可能需要UPDATE语义,并且会对实际结果感到不愉快的惊讶。

build议的UPSERT实现中的诡计基本上是使用INSERT OR REPLACE,但指定所有字段,使用embedded式SELECT子句检索不希望更改的字段的当前值。

我认为值得指出的是,如果您不完全了解PRIMARY KEYUNIQUE如何交互,那么在这里可能会出现一些意外的行为。

作为一个例子,如果你想插入一个logging,只有当NAME字段当前没有被采用,如果是,你想要一个约束exception来触发,那么INSERT OR REPLACE将不会抛出exception,而是将通过replace冲突的logging(现有logging与相同的名称 )来解决UNIQUE约束本身。 加斯帕德在上面的回答中certificate了这一点。

如果您想要触发约束exception,则必须使用INSERT语句,并且在知道该名称未被占用后,依靠单独的UPDATE命令更新logging。