Frequentemente encontramos a situação "Se não existir, insira". O blog de Dan Guzman tem uma excelente investigação sobre como tornar esse processo seguro para threads.
Eu tenho uma tabela básica que simplesmente cataloga uma string para um número inteiro de um arquivo SEQUENCE
. Em um procedimento armazenado, preciso obter a chave inteira para o valor, se existir, ou INSERT
obter o valor resultante. Há uma restrição de exclusividade na dbo.NameLookup.ItemName
coluna, portanto, a integridade dos dados não está em risco, mas não quero encontrar as exceções.
Não é um IDENTITY
então não consigo SCOPE_IDENTITY
e o valor pode ser NULL
em certos casos.
Na minha situação, só tenho que lidar com INSERT
a segurança na mesa, então estou tentando decidir se é melhor praticar usar MERGE
assim:
SET NOCOUNT, XACT_ABORT ON;
DECLARE @vValueId INT
DECLARE @inserted AS TABLE (Id INT NOT NULL)
MERGE
dbo.NameLookup WITH (HOLDLOCK) AS f
USING
(SELECT @vName AS val WHERE @vName IS NOT NULL AND LEN(@vName) > 0) AS new_item
ON f.ItemName= new_item.val
WHEN MATCHED THEN
UPDATE SET @vValueId = f.Id
WHEN NOT MATCHED BY TARGET THEN
INSERT
(ItemName)
VALUES
(@vName)
OUTPUT inserted.Id AS Id INTO @inserted;
SELECT @vValueId = s.Id FROM @inserted AS s
Eu poderia fazer isso sem usar MERGE
apenas um condicional INSERT
seguido por um SELECT
. Acho que esta segunda abordagem é mais clara para o leitor, mas não estou convencido de que seja uma prática "melhor"
SET NOCOUNT, XACT_ABORT ON;
INSERT INTO
dbo.NameLookup (ItemName)
SELECT
@vName
WHERE
NOT EXISTS (SELECT * FROM dbo.NameLookup AS t WHERE @vName IS NOT NULL AND LEN(@vName) > 0 AND t.ItemName = @vName)
DECLARE @vValueId int;
SELECT @vValueId = i.Id FROM dbo.NameLookup AS i WHERE i.ItemName = @vName
Ou talvez haja outra maneira melhor que não considerei
Pesquisei e fiz referência a outras perguntas. Este: https://stackoverflow.com/questions/5288283/sql-server-insert-if-not-exists-best-practice é o mais apropriado que encontrei, mas não parece muito aplicável ao meu caso de uso. Outras questões para a IF NOT EXISTS() THEN
abordagem que não acho aceitável.