代码之家  ›  专栏  ›  技术社区  ›  SparkyNZ

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

  •  247
  • SparkyNZ  · 技术社区  · 14 年前

    我有一个表定义如下:

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

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

    有人能告诉我怎么做吗?

    9 回复  |  直到 4 年前
        1
  •  340
  •   janm    10 年前

    看一看 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"));
    
        2
  •  101
  •   imans77    6 年前

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

    第一个命令将插入记录。如果记录存在,它将忽略由于与现有主键冲突而导致的错误。

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

        3
  •  69
  •   Anna B    14 年前

    您需要在表上设置一个约束以触发“ conflict

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

    “从数据中选择*”将为您提供:

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

        4
  •  36
  •   Burcin    14 年前

    先更新一下。如果 受影响的行计数 =0,然后插入。这是最简单的,适合所有人 关系数据库

        5
  •  29
  •   Steely Wing    4 年前

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

    sqlite> CREATE TABLE Book (
      ID     INTEGER PRIMARY KEY AUTOINCREMENT,
      Name   TEXT,
      TypeID INTEGER,
      Level  INTEGER,
      Seen   INTEGER
    );
    
    sqlite> INSERT INTO Book VALUES (1001, 'C++', 10, 10, 0);
    
    sqlite> SELECT * FROM Book;
    1001|C++|10|10|0
    
    sqlite> INSERT OR REPLACE INTO Book(ID, Name) VALUES(1001, 'SQLite');
    
    sqlite> SELECT * FROM Book;
    1001|SQLite|||
    

    如果要保留另一个字段

    • 方法1
    sqlite> SELECT * FROM Book;
    1001|C++|10|10|0
    
    sqlite> INSERT OR IGNORE INTO Book(ID) VALUES(1001);
    sqlite> UPDATE Book SET Name='SQLite' WHERE ID=1001;
    
    sqlite> SELECT * FROM Book;
    1001|SQLite|10|10|0
    
    • 方法2

    UPSERT (使用版本3.24.0(2018-06-04)将语法添加到SQLite)

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

    excluded. VALUES ( 'SQLite' ).

        6
  •  20
  •   jww avp    5 年前

    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 ... 你的选择至少需要 WHERE true 解决语法分析器对标记的歧义 ON

    请注意 INSERT OR REPLACE...

        7
  •  6
  •   matt    9 年前

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

    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';
    
        8
  •  4
  •   Community Nick Dandoulakis    7 年前

    我相信你想要 UPSERT .

    “INSERT OR REPLACE”如果不使用该答案中的其他技巧,则会将未指定的任何字段重置为NULL或其他默认值。(INSERT或REPLACE的这种行为不同于UPDATE;它与INSERT完全相同,因为它实际上是INSERT;但是如果您想要的是updateif exists,那么您可能需要UPDATE语义,并且会对实际结果感到不快。)

        9
  •  1
  •   Community Nick Dandoulakis    7 年前

    我认为有必要指出的是,如果你不完全理解怎么做,这里可能会有一些意想不到的行为 主键 独一无二的 互动。

    例如,如果您只想在 姓名 不会抛出和异常,而是解决 通过替换冲突记录(使用相同的 ). Gaspard's his answer 上面。

    声明,并依赖于一个单独的 更新 命令更新记录,一旦你知道该名称是没有采取。