Вставка новой строки без переопределения столбцов, если новое значение столбца равно нулю - PullRequest
0 голосов
/ 31 октября 2018

Скажем, у меня есть таблица MyTableName с тремя столбцами: COLUMN_NAME_A, COLUMN_NAME_B, COLUMN_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];

}

1 Ответ

0 голосов
/ 01 ноября 2018

Я думаю, у вас есть 2 варианта. Первый уродлив и, вероятно, медленнее, но, насколько я знаю, это стандартный 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'))
);

Это довольно просто, но немного уродливо и потенциально медленно. Чем больше у вас столбцов, тем больше встроенных выделений вам нужно сделать (на самом деле они нужны только для столбцов с потенциальными нулевыми значениями, но все же), и чем больше строк, тем больше времени занимает выбор.

Upsert

Но если вы используете SQLite версии 3.24.0 или новее, вы можете использовать так называемый upsert синтаксис

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_ ссылается на новое значение, которое будет вставлено (которое «исключено», пока мы не разрешим конфликт).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...