Quero inserir dados na minha tabela, mas inserir apenas dados que ainda não existem no meu banco de dados.
Aqui está o meu código:
ALTER PROCEDURE [dbo].[EmailsRecebidosInsert]
(@_DE nvarchar(50),
@_ASSUNTO nvarchar(50),
@_DATA nvarchar(30) )
AS
BEGIN
INSERT INTO EmailsRecebidos (De, Assunto, Data)
VALUES (@_DE, @_ASSUNTO, @_DATA)
WHERE NOT EXISTS ( SELECT * FROM EmailsRecebidos
WHERE De = @_DE
AND Assunto = @_ASSUNTO
AND Data = @_DATA);
END
E o erro é:
Mensagem 156, Nível 15, Estado 1, Procedimento EmailsRecebidosInsert, Linha 11
Sintaxe incorreta perto da palavra-chave 'WHERE'.
sql
sql-server
sql-server-2008
stored-procedures
Francisco Carvalho
fonte
fonte
insert
declaração é sempre uma única transação. Não é como se o SQL Server avaliasse a subconsulta primeiro e depois, em algum momento posterior, e sem manter um bloqueio, continue fazendo a inserção.Respostas:
em vez de abaixo do código
substituir com
Atualizada : (obrigado a @Marc Durdin por apontar)
Observe que, sob carga alta, isso ainda falha algumas vezes, porque uma segunda conexão pode passar no teste SE NÃO EXISTE antes que a primeira conexão execute o INSERT, ou seja, uma condição de corrida. Consulte stackoverflow.com/a/3791506/1836776 para obter uma boa resposta sobre por que nem mesmo o encapsulamento em uma transação resolve isso.
fonte
select *
, neste caso, não faz diferença alguma porque está sendo usado em umaEXISTS
cláusula. O SQL Server sempre o otimiza e o faz há séculos. Como sou muito velho, geralmente escrevo essas consultas como,EXISTS (SELECT 1 FROM...)
mas não são mais necessárias.Para aqueles que procuram o caminho mais rápido , me deparei recentemente com esses benchmarks onde aparentemente usar "INSERT SELECT ... EXCEPT SELECT ..." acabou sendo o mais rápido para 50 milhões de registros ou mais.
Aqui está um exemplo de código do artigo (o terceiro bloco de código foi o mais rápido):
fonte
Eu usaria uma mesclagem:
fonte
Experimente o código abaixo
fonte
O
INSERT
comando não possui umaWHERE
cláusula - você terá que escrevê-lo assim:fonte
Eu fiz a mesma coisa com o SQL Server 2012 e funcionou
fonte
Dependendo da sua versão (2012?) Do SQL Server, além do IF EXISTS, você também pode usar o MERGE da seguinte forma:
fonte
SQL diferente, mesmo princípio. Inserir apenas se a cláusula em que não existe falhar
fonte
Conforme explicado no código abaixo: Execute as consultas abaixo e verifique você mesmo.
Inserir um registro:
Agora, tente inserir o mesmo registro novamente:
Insira um registro diferente:
fonte
Você poderia usar o
GO
comando Isso reiniciará a execução das instruções SQL após um erro. No meu caso, tenho algumas instruções 1000 INSERT, onde já existem alguns desses registros no banco de dados, simplesmente não sei quais. Descobri que, depois de processar alguns 100, a execução para com uma mensagem de erro que não pode,INSERT
pois o registro já existe. Muito chato, mas colocando umGO
resolvido isso. Pode não ser a solução mais rápida, mas a velocidade não era o meu problema.fonte
GO
é um separador de lotes? Não ajuda a impedir registros duplicados.