Estou usando SQL dinâmico para inserir um valor padrão em uma tabela e quero retornar o SCOPE_IDENTITY()
valor para minha surrogate key. No entanto, SCOPE_IDENTITY()
está retornando NULL
por algum motivo. Estou esquecendo de algo?
Obrigado!
DECLARE @SQL NVARCHAR(MAX),
@SurrogateKey INT,
@SchemaName VARCHAR(128) = 'dim',
@TableName VARCHAR(128) = 'Sales',
@NaturalKeyColumn VARCHAR(128) = 'SalesID',
@NaturalKeyValue VARCHAR(40) = '100',
@SurrogateKeyColumn VARCHAR(128) = 'SalesKey';
SET @SQL = N'SELECT @SurrogateKey = ' + QUOTENAME(@SurrogateKeyColumn) +
' FROM ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@TableName) +
' WHERE ' + QUOTENAME(@NaturalKeyColumn) + ' = @NaturalKeyValue';
EXEC sp_executesql @SQL, N'@SurrogateKey INT OUTPUT, @NaturalKeyValue VARCHAR(40)', @SurrogateKey OUTPUT, @NaturalKeyValue;
IF @SurrogateKey IS NULL
BEGIN
BEGIN TRANSACTION;
SET @SQL = N'INSERT INTO ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@TableName) +
' (' + QUOTENAME(@NaturalKeyColumn) + ', InferredFlag)
VALUES (@NaturalKeyValue, 1)';
EXEC sp_executesql @SQL, N'@NaturalKeyValue VARCHAR(40)', @NaturalKeyValue;
-- Check if the INSERT was successful
IF @@ROWCOUNT > 0
BEGIN
SET @SQL = N'SELECT @SurrogateKey = SCOPE_IDENTITY()';
EXEC sp_executesql @SQL, N'@SurrogateKey INT OUTPUT', @SurrogateKey OUTPUT;
END
COMMIT TRANSACTION;
END
SELECT @SurrogateKey;
SCOPE_IDENTITY()
sem surpresas só funciona dentro de um único escopo. Você precisa criar e executar um único lote SQL dinâmico. Isso também é muito mais eficiente.Outros problemas com seu código:
SELECT
.SELECT
, caso contrário, um bloqueio compartilhado é obtido, o que não vai ajudar você. Você precisa deSERIALIZABLE
eUPDLOCK
aqui.sysname
variáveis, que é um alias paranvarchar(128)
.XACT_ABORT ON
deve ser usado para que as reversões ocorram corretamente em caso de erros.SELECT
diretamente do SQL dinâmico. Não precisa doOUT
parâmetro, a menos que precise do valor posteriormente no lado estático.