如果列的新值为null,则插入新行而不覆盖列



假设我有一个表MyTableName,它有三列:COLUMN_NAME_ACOLUMN_NAME_BCOLUMN_NAME_C(为了简化起见,只有三列,实际上我可能有几十列(。在我当前的实现中,当我插入新行时,所有列都将被覆盖。如何仅覆盖新值不为null的列。一种方法是检查新值,如果它为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];
}

我认为您有两个选项。第一个很难看,可能速度较慢,但据我所知,它是标准SQL,并且得到了广泛支持。第二个不是标准的,但SQLite自3.24.0版本起就支持它。

嵌入式选择

根据这个答案,你可以做一些类似的事情

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

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

Upsert

但是,如果您使用的是SQLite 3.24.0或更新版本,您可以使用所谓的upstart语法

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_是指要插入的新值(在我们解决冲突之前,它是"排除的"(。

最新更新