【问题标题】:Inserting a new row without overriding columns if the new value of the column is null如果列的新值为空,则插入新行而不覆盖列
【发布时间】:2019-04-04 10:54:29
【问题描述】:

假设我有一个表MyTableName 有三列:COLUMN_NAME_ACOLUMN_NAME_BCOLUMN_NAME_C(为了简化,只有三列,实际上我可能有几十列)。在我当前的实现中,当我插入新行时,所有列都将被覆盖。如何仅覆盖新值不为空的列。一种方法是检查新值,如果它为 NULL,则从表中读取值并重写它。 有没有更简单和/通用的方法?

- (void)insertEntries:(<id<PTDBGeneralInfoTableEntry>>)entry inDatabase:(FMDatabase *)db {

  [db beginTransaction];

  [self createTableInDatabase:db];

  NSString *insertSQL = [NSString stringWithFormat:@"INSERT OR REPLACE INTO MyTableName"
                         "(%@, %@, %@)"
                         " VALUES(?, ?, ?)",
                         COLUMN_NAME_A,
                         COLUMN_NAME_B,
                         COLUMN_NAME_C];

  NSArray* values = @[entry.valueA ? entry.valueA : [NSNull null],
                      entry.valueB ? entry.valueB : [NSNull null],
                      entry.ValueC ? entry.ValueC : [NSNull null]];

  BOOL res = [db executeUpdate:insertSQL withArgumentsInArray:values];


  [db commit];
}

- (void)createTableInDatabase:(FMDatabase *)db {

  NSString* createTableSQL =
  [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ ("
   "%@ TEXT NOT NULL PRIMARY KEY,"
   "%@ INTEGER,"            
   "%@ REAL"             
   ")",
   COLUMN_NAME_A,
   COLUMN_NAME_B
   COLUMN_NAME_C
   ];

   [db executeUpdate:createTableSQL];

}

【问题讨论】:

    标签: objective-c sqlite sql-update


    【解决方案1】:

    我认为您有两个选择。第一个是丑陋的,可能更慢,但据我所知是标准 SQL 并得到广泛支持。第二个不是标准的,但 SQLite 从 3.24.0 版本开始支持。

    嵌入式选择

    基于this answer,你可以做类似的事情

    INSERT OR REPLACE INTO MyTableName
    VALUES (
        'example_id',
         COALESCE(100, (SELECT COLUMN_NAME_B from MyTableName WHERE COLUMN_NAME_A = 'example_id')),
         COALESCE(1.0, (SELECT COLUMN_NAME_C from MyTableName WHERE COLUMN_NAME_A = 'example_id'))
    );
    

    这相当简单,但也有点难看,而且可能很慢。您拥有的列越多,您需要执行的嵌入选择就越多(实际上您只需要它们用于具有潜在空值的列,但仍然如此),并且您拥有的行越多,选择所花费的时间就越多。

    更新插入

    但如果您使用的是 SQLite 3.24.0 或更高版本,则可以使用所谓的upsert syntax

    INSERT INTO MyTableName
    VALUES ('example_id', 100, 1.0)
    ON CONFLICT(COLUMN_NAME_A) DO UPDATE SET
        COLUMN_NAME_B = COALESCE(EXCLUDED.COLUMN_NAME_B, COLUMN_NAME_B),
        COLUMN_NAME_C = COALESCE(EXCLUDED.COLUMN_NAME_C, COLUMN_NAME_C);
    

    其中 EXCLUDED.COLUMN_NAME_ 指的是要插入的新值(在我们解决冲突之前,它是“排除的”)。

    【讨论】:

    • 我得到:'接近“ON”:语法错误'。我的 Sqlite 版本是 3.24.0
    • 这很奇怪,它似乎对我有用。我的确切版本是:sqlite&gt;.version SQLite 3.24.0 2018-06-04 19:24:41 c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca zlib version 1.2.11 gcc-5.2.0
    • 顺便说一句,我使用的是 Windows 10,使用的是从官方网站 sqlite.org/download.html 下载的预编译二进制文件。链接已更新为指向 3.25.2,但原始 URL 仍然有效。
    猜你喜欢
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 2014-12-16
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多