Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

SQL Server, Como definir o incremento automático após criar uma tabela sem perda de dados?


Alterando a IDENTITY é realmente uma mudança apenas de metadados. Mas para atualizar os metadados diretamente requer iniciar a instância no modo de usuário único e mexer em algumas colunas em sys.syscolpars e não é documentado/sem suporte e não é algo que eu recomendaria ou forneceria detalhes adicionais.

Para as pessoas que se deparam com esta resposta no SQL Server 2012+, de longe, a maneira mais fácil de obter esse resultado de uma coluna de incremento automático seria criar uma SEQUENCE object e defina o next value for seq como o padrão da coluna.

Alternativamente, ou para versões anteriores (de 2005 em diante), a solução postada neste item de conexão mostra uma maneira totalmente suportada de fazer isso sem a necessidade de operações de tamanho de dados usando ALTER TABLE...SWITCH . Também blogou sobre no MSDN aqui. Embora o código para conseguir isso não seja muito simples e haja restrições - como a tabela que está sendo alterada não pode ser alvo de uma restrição de chave estrangeira.

Código de exemplo.

Configurar tabela de teste sem identity coluna.

CREATE TABLE dbo.tblFoo 
(
bar INT PRIMARY KEY,
filler CHAR(8000),
filler2 CHAR(49)
)


INSERT INTO dbo.tblFoo (bar)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master..spt_values v1, master..spt_values v2

Altere-o para ter uma identity coluna (mais ou menos instantânea).

BEGIN TRY;
    BEGIN TRANSACTION;

    /*Using DBCC CHECKIDENT('dbo.tblFoo') is slow so use dynamic SQL to
      set the correct seed in the table definition instead*/
    DECLARE @TableScript nvarchar(max)
    SELECT @TableScript = 
    '
    CREATE TABLE dbo.Destination(
        bar INT IDENTITY(' + 
                     CAST(ISNULL(MAX(bar),0)+1 AS VARCHAR) + ',1)  PRIMARY KEY,
        filler CHAR(8000),
        filler2 CHAR(49)
        )

        ALTER TABLE dbo.tblFoo SWITCH TO dbo.Destination;
    '       
    FROM dbo.tblFoo
    WITH (TABLOCKX,HOLDLOCK)

    EXEC(@TableScript)


    DROP TABLE dbo.tblFoo;

    EXECUTE sp_rename N'dbo.Destination', N'tblFoo', 'OBJECT';


    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
    PRINT ERROR_MESSAGE();
END CATCH;

Teste o resultado.

INSERT INTO dbo.tblFoo (filler,filler2) 
OUTPUT inserted.*
VALUES ('foo','bar')

bar         filler    filler2
----------- --------- ---------
10001       foo       bar      

Limpeza

DROP TABLE dbo.tblFoo