Encontrei algumas soluções "seria" para o clássico "Como insiro um novo registro ou atualizo um, se ele já existe", mas não consigo fazer com que nenhum deles funcione no SQLite.
Eu tenho uma tabela definida da seguinte maneira:
CREATE TABLE Book
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
O que eu quero fazer é adicionar um registro com um nome exclusivo. Se o nome já existir, desejo modificar os campos.
Alguém pode me dizer como fazer isso, por favor?
Respostas:
Dê uma olhada em http://sqlite.org/lang_conflict.html .
Você quer algo como:
Observe que qualquer campo que não esteja na lista de inserção será definido como NULL se a linha já existir na tabela. É por isso que existe uma subseleção para a
ID
coluna: no caso de substituição, a instrução o definiria como NULL e, em seguida, um novo ID seria alocado.Essa abordagem também pode ser usada se você desejar deixar valores específicos de campo em paz se a linha no caso de substituição, mas definir o campo como NULL no caso de inserção.
Por exemplo, supondo que você queira sair
Seen
sozinho:fonte
Level
, essa abordagem não poderá ser seguida.Você deve usar o
INSERT OR IGNORE
comando seguido por umUPDATE
comando: No exemplo a seguirname
é uma chave primária:O primeiro comando irá inserir o registro. Se o registro existir, ele ignorará o erro causado pelo conflito com uma chave primária existente.
O segundo comando atualizará o registro (que agora existe definitivamente)
fonte
Você precisa definir uma restrição na tabela para acionar um " conflito " que será resolvido fazendo uma substituição:
Então você pode emitir:
O "SELECT * FROM data" fornece:
Observe que o data.id é "3" e não "1" porque REPLACE faz um DELETE e INSERT, não um UPDATE. Isso também significa que você deve garantir que define todas as colunas necessárias ou obterá valores NULL inesperados.
fonte
Primeiro, atualize-o. Se a contagem de linhas afetadas = 0, insira-a. É o mais fácil e adequado para todos os RDBMS .
fonte
Insert or Replace
é realmente mais preferível.INSERT OR REPLACE
substituirá os outros campos para o valor padrão.Se você deseja preservar o outro campo
ou usando UPSERT (a sintaxe foi adicionada ao SQLite com a versão 3.24.0 (04/06/2018))
O
excluded.
prefixo igual ao valor emVALUES
.fonte
Upsert é o que você quer.
UPSERT
A sintaxe foi adicionada ao SQLite com a versão 3.24.0 (04/06/2018).Esteja avisado de que, neste momento, a palavra real "UPSERT" não faz parte da sintaxe de upsert.
A sintaxe correta é
INSERT INTO ... ON CONFLICT(...) DO UPDATE SET...
e se você estiver fazendo
INSERT INTO SELECT ...
suas necessidades selecionadas, pelo menos,WHERE true
para resolver a ambiguidade do analisador sobre o tokenON
com a sintaxe de junção.Esteja avisado de que
INSERT OR REPLACE...
excluirá o registro antes de inserir um novo, caso seja necessário substituí-lo, o que pode ser ruim se houver cascatas de chaves estrangeiras ou outros gatilhos de exclusão.fonte
UPSERT
sintaxe.Se você não tiver uma chave primária, poderá inserir, se não existir, e faça uma atualização. A tabela deve conter pelo menos uma entrada antes de usá-la.
fonte
Eu acredito que você quer UPSERT .
"INSERIR OU SUBSTITUIR" sem os truques adicionais nessa resposta redefinirá todos os campos que você não especificar para NULL ou outro valor padrão. (Esse comportamento de INSERT OR REPLACE é diferente de UPDATE; é exatamente como INSERT, porque na verdade é INSERT; no entanto, se o que você deseja é UPDATE-se-existe, provavelmente deseja a semântica UPDATE e ficará desagradável com o resultado real.)
O truque da implementação sugerida do UPSERT é basicamente usar INSERT OR REPLACE, mas especifique todos os campos, usando cláusulas SELECT incorporadas para recuperar o valor atual dos campos que você não deseja alterar.
fonte
Eu acho que vale ressaltar que pode haver algum comportamento inesperado aqui, se você não entender completamente como PRIMARY KEY e UNIQUE interagem.
Como exemplo, se você deseja inserir um registro apenas se o campo NAME não estiver atualmente ocupado, e se desejar, uma exceção de restrição será acionada para informar, INSERT OR REPLACE não lançará uma exceção e, em vez disso, será acionado. resolver o UNIQUE restrição substituindo o registro conflitante (o registro existente com o mesmo NAME ). Gaspard's demonstra isso muito bem em sua resposta acima.
Se você deseja que uma exceção de restrição seja acionada, use uma instrução INSERT e conte com um comando UPDATE separado para atualizar o registro quando souber que o nome não foi usado.
fonte