SQLite - UPSERT *not* INSERT or REPLACE

后端 未结 18 2895
猫巷女王i
猫巷女王i 2020-11-21 23:53

http://en.wikipedia.org/wiki/Upsert

Insert Update stored proc on SQL Server

Is there some clever way to do this in SQLite that I have not thought of?

18条回答
  •  刺人心
    刺人心 (楼主)
    2020-11-22 00:26

    Here is a solution that really is an UPSERT (UPDATE or INSERT) instead of an INSERT OR REPLACE (which works differently in many situations).

    It works like this:
    1. Try to update if a record with the same Id exists.
    2. If the update did not change any rows (NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0)), then insert the record.

    So either an existing record was updated or an insert will be performed.

    The important detail is to use the changes() SQL function to check if the update statement hit any existing records and only perform the insert statement if it did not hit any record.

    One thing to mention is that the changes() function does not return changes performed by lower-level triggers (see http://sqlite.org/lang_corefunc.html#changes), so be sure to take that into account.

    Here is the SQL...

    Test update:

    --Create sample table and records (and drop the table if it already exists)
    DROP TABLE IF EXISTS Contact;
    CREATE TABLE [Contact] (
      [Id] INTEGER PRIMARY KEY, 
      [Name] TEXT
    );
    INSERT INTO Contact (Id, Name) VALUES (1, 'Mike');
    INSERT INTO Contact (Id, Name) VALUES (2, 'John');
    
    -- Try to update an existing record
    UPDATE Contact
    SET Name = 'Bob'
    WHERE Id = 2;
    
    -- If no record was changed by the update (meaning no record with the same Id existed), insert the record
    INSERT INTO Contact (Id, Name)
    SELECT 2, 'Bob'
    WHERE NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0);
    
    --See the result
    SELECT * FROM Contact;
    

    Test insert:

    --Create sample table and records (and drop the table if it already exists)
    DROP TABLE IF EXISTS Contact;
    CREATE TABLE [Contact] (
      [Id] INTEGER PRIMARY KEY, 
      [Name] TEXT
    );
    INSERT INTO Contact (Id, Name) VALUES (1, 'Mike');
    INSERT INTO Contact (Id, Name) VALUES (2, 'John');
    
    -- Try to update an existing record
    UPDATE Contact
    SET Name = 'Bob'
    WHERE Id = 3;
    
    -- If no record was changed by the update (meaning no record with the same Id existed), insert the record
    INSERT INTO Contact (Id, Name)
    SELECT 3, 'Bob'
    WHERE NOT EXISTS(SELECT changes() AS change FROM Contact WHERE change <> 0);
    
    --See the result
    SELECT * FROM Contact;
    

提交回复
热议问题