SQLite: возможно обновить строку или вставить, если она не существует? - PullRequest
12 голосов
/ 17 августа 2010

Я уверен, что могу проверить, существует ли строка, выбрав ее, но мне интересно, есть ли более скользкий способ, о котором я просто не знаю - это кажется достаточно распространенной задачей, которая может быть. Эта таблица SQLite выглядит примерно так:

rowID  QID    ANID  value
------ ------ ----- ------
0      axo    1     45
1      axo    2     12

Если комбинация QID и ANID уже существует, это значение следует обновить, если комбинация QID и ANID еще не существует, то ее следует вставить. Пока достаточно просто написать:

SELECT * where QID = 'axo' and ANID = 3;

И проверь, если строка существует, тогда ответвление и / или вставка / обновление, я не могу помочь, но ищу лучший путь. Заранее спасибо!

Ответы [ 4 ]

14 голосов
/ 04 января 2012

Осторожно : REPLACE на самом деле не равен 'UPDATE OR INSERT' ... REPLACE заменяет всю строку. Поэтому, если вы не укажете значения для КАЖДОГО столбца, вы замените неуказанные столбцы значением NULL или значениями по умолчанию.

В простом примере, подобном приведенному выше, это, вероятно, хорошо, но если вы привыкнете использовать REPLACE в качестве «UPDATE OR INSERT», вы обнуляете данные, когда забываете указывать значение для каждого поля ... просто предупреждение из опыта.

10 голосов
/ 17 августа 2010

Документация insert подробно описывает параметр REPLACE

INSERT OR REPLACE INTO tabname (QID,ANID,value) VALUES ('axo',3,45)

«ВСТАВИТЬ ИЛИ ЗАМЕНИТЬ» можно сократить до «ЗАМЕНИТЬ».

Пример в Perl

Пересмотрен следующий пример для использования составного первичного ключа

use strict;
use DBI;

### Connect to the database via DBI
my $dbfile = "simple.db";
unlink $dbfile;
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile");

### Create a table
$dbh->do("CREATE TABLE tblData (qid TEXT, anid INTEGER, value INTEGER, PRIMARY KEY(qid, anid))");

### Add some data
my $insert = $dbh->prepare("INSERT INTO tblData (qid,anid,value) VALUES (?,?,?)");

$insert->execute('axo', 1, 45);
$insert->execute('axo', 2, 12);

$insert->finish;

### Update data
my $insert_update = $dbh->prepare("REPLACE INTO tblData (qid,anid,value) VALUES (?,?,?)");

$insert_update->execute('axo', 2, 500);
$insert_update->execute('axo', 10, 500);

$insert_update->finish;

### Print out the data
my $select = $dbh->prepare("SELECT * FROM tblData ORDER BY 1,2");
$select->execute;

while (my @row = $select->fetchrow_array()) {
    printf "Row: %s\n", join(" - ", @row);
}

$select->finish;

$dbh->disconnect;
exit 0;

Создает следующий вывод, демонстрирующий обновление одной строки и вставку другой

Row: axo - 1 - 45
Row: axo - 2 - 500
Row: axo - 10 - 500
4 голосов
/ 17 августа 2010

вы можете использовать команду REPLACE. Docs

1 голос
/ 18 августа 2010

В этой конкретной ситуации оказывается, что нет простого решения - по крайней мере, я не смог его найти, несмотря на попытки Марка предложить его.

Решение, которое я нашелИспользование может быть полезным для кого-то другого, поэтому я публикую его здесь.

Я определил первичный ключ из нескольких столбцов как QID + ANID и попытался вставить его в таблицу.Если эта конкретная комбинация существует, она выдаст код ошибки 23000, который я затем смогу использовать с указателем, что вместо этого должно быть ОБНОВЛЕНИЕ.Вот основная идея (в PHP):

try {
  $DB->exec("INSERT INTO tblData (QID,ANID,value) VALUES ('xxx','x',1)");
}
catch(PDOException $e) {
  if($e->getCode() == 23000) {
    $DB->exec("UPDATE tblData SET value=value+1 WHERE ANID='x' AND QID='xxx'");
  }
}

Фактический код, который я использовал, немного сложнее с использованием prepare / placeholder и обработкой ошибки, если код не 23000 и т. Д.

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