Como você trunca todas as tabelas em um banco de dados usando o TSQL?

204

Eu tenho um ambiente de teste para um banco de dados que quero recarregar com novos dados no início de um ciclo de teste. Não estou interessado em reconstruir o banco de dados inteiro - simplesmente "redefinindo" os dados.

Qual é a melhor maneira de remover todos os dados de todas as tabelas usando o TSQL? Existem procedimentos, visualizações etc. do sistema armazenados que podem ser usados? Eu não quero criar e manter manualmente instruções de tabela truncadas para cada tabela - eu preferiria que fosse dinâmico.

Raio
fonte

Respostas:

188

Para o SQL 2005,

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

Mais alguns links para 2000 e 2005/2008 .

Gulzar Nazim
fonte
62
Você não pode truncar tabelas que possuem chaves estrangeiras, portanto, isso funcionará apenas se não houver restrições de chave estrangeira entre as tabelas (ou elas foram desativadas).
marcj
1
agreed..i pensava desde que ele pediu para truncar tabelas, ele já resolveu o problema com chaves estrangeiras ..
Gulzar Nazim
@ gulzar- mais ou menos- eu postei uma pergunta separada sobre como lidar com os FKs, mas sua resposta tem seus próprios méritos.
Ray
11
@ Sam: Não, não vai! Os dados nas tabelas são irrelevantes. Enquanto houver uma restrição de chave estrangeira referenciando a tabela (mesmo uma desativada), você não poderá truncá-la.
TToni
3
'EXEC sp_MSForEachTable' DROP TABLE? ' Trabalhando muito bem :) (encantando todas as tabelas de banco de dados)
kuncevic.dev
419

Ao lidar com a exclusão de dados de tabelas que possuem relacionamentos de chave estrangeira - o que é basicamente o caso de qualquer banco de dados projetado adequadamente - podemos desativar todas as restrições, excluir todos os dados e reativar as restrições.

-- disable all constraints
EXEC sp_MSForEachTable "ALTER TABLE ? NOCHECK CONSTRAINT all"

-- delete data in all tables
EXEC sp_MSForEachTable "DELETE FROM ?"

-- enable all constraints
exec sp_MSForEachTable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

Mais sobre como desativar restrições e gatilhos aqui

se algumas das tabelas tiverem colunas de identidade, convém realizá-las novamente

EXEC sp_MSForEachTable "DBCC CHECKIDENT ( '?', RESEED, 0)"

Observe que o comportamento do RESEED difere entre uma tabela nova em folha e uma que teve alguns dados inseridos anteriormente no BOL :

DBCC CHECKIDENT ('nome_tabela', RESEED, newReseedValue)

O valor atual da identidade é definido como newReseedValue. Se nenhuma linha foi inserida na tabela desde que foi criada, a primeira linha inserida após a execução do DBCC CHECKIDENT usará newReseedValue como identidade. Caso contrário, a próxima linha inserida usará newReseedValue + 1. Se o valor de newReseedValue for menor que o valor máximo na coluna de identidade, a mensagem de erro 2627 será gerada nas referências subseqüentes à tabela.

Obrigado a Robert por apontar o fato de que desabilitar restrições não permite o uso de truncado, as restrições teriam que ser eliminadas e depois recriadas

Kristof
fonte
34
Desabilitar restrições NÃO permitirá truncamento de tabelas referenciadas por uma restrição FOREIGN KEY. A restrição FK deve ser eliminada. Por favor, responda se estiver errado sobre isso, mas não encontrei nenhuma maneira de evitar descartá-los.
3111 Robert Claypool
1
Apenas um erro de digitação "Tabela" não deve estar presente nesta instrução EXEC sp_MSForEachTable "DELETE FROM TABLE?" A versão correta deve ser: EXEC sp_MSForEachTable "DELETE FROM?"
Raghav
4
Se você estiver usando o SSMS 2008 ou mais recente, provavelmente desejará adicionar SET ROWCOUNT 0no início do seu script, pois o padrão é limitar as ações a 500 linhas! Você receberá erros frustrantes como eu, porque nem todos os dados foram realmente excluídos.
Sean Hanley
1
Isso funcionou muito bem. No meu caso, também tive que adicionar EXEC sp_msforeachtable "ALTER TABLE? Desativar TRIGGER all" e EXEC sp_msforeachtable "ALTER TABLE? Ativar TRIGGER all" Antes e depois da instrução delete.
RobC
2
Minha resposta favorita. Mas por que você (todos, até os comentadores) coloca seqüências de caracteres literais SQL entre aspas duplas?
bitoolean
57

Aqui está o rei papai dos scripts de limpeza de banco de dados. Ele limpa todas as tabelas e as repassa corretamente:

SET QUOTED_IDENTIFIER ON;
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? NOCHECK CONSTRAINT ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? DISABLE TRIGGER ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? CHECK CONSTRAINT ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? ENABLE TRIGGER ALL' 
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON';

IF NOT EXISTS (
    SELECT
        *
    FROM
        SYS.IDENTITY_COLUMNS
        JOIN SYS.TABLES ON SYS.IDENTITY_COLUMNS.Object_ID = SYS.TABLES.Object_ID
    WHERE
        SYS.TABLES.Object_ID = OBJECT_ID('?') AND SYS.IDENTITY_COLUMNS.Last_Value IS NULL
)
AND OBJECTPROPERTY( OBJECT_ID('?'), 'TableHasIdentity' ) = 1

    DBCC CHECKIDENT ('?', RESEED, 0) WITH NO_INFOMSGS;

Aproveite, mas tenha cuidado!

Chris KL
fonte
2
Infelizmente, o comando acima falha se você tiver calculado as colunas, pois o sp_MSforeachtable aparentemente possui SET QUOTED_IDENTITY OFFem seu corpo ( link ). ATUALIZAÇÃO: a correção é adicionar "SET QUOTED_IDENTIFIERS on;" para o início de cada instrução que gera esse erro (conforme mencionado aqui )
March
1
parece que isso não
propagou novamente
48

A maneira mais simples de fazer isso é

  1. abrir o SQL Management Studio
  2. navegue para o seu banco de dados
  3. Clique com o botão direito do mouse e selecione Tarefas-> Gerar Scripts (foto 1)
  4. Na tela "escolher objetos", selecione a opção "selecionar objetos específicos" e marque "tabelas" (foto 2)
  5. na próxima tela, selecione "avançado" e altere a opção "Script DROP and CREATE" para "Script DROP and CREATE" (foto 3)
  6. Escolha salvar o script em uma nova janela do editor ou em um arquivo e execute conforme necessário.

isso fornecerá um script que descarta e recria todas as suas tabelas sem a necessidade de se preocupar com a depuração ou se você incluiu tudo. Enquanto isso executa mais do que apenas um truncado, os resultados são os mesmos. Lembre-se de que suas chaves primárias de incremento automático começarão em 0, em vez de tabelas truncadas que lembrarão o último valor atribuído. Você também pode executar isso a partir do código se não tiver acesso ao Management studio em seus ambientes de pré-produto ou produção.

1

insira a descrição da imagem aqui

2)

insira a descrição da imagem aqui

3)

insira a descrição da imagem aqui

Capitão Kenpachi
fonte
1
Cuidado se você usar isso para um banco de dados com um esquema muito complexo. Eu tentei em uma cópia do desenvolvedor do nosso banco de dados de produção e destruiu o esquema, exigindo uma reimplantação total.
usar o seguinte código
1
Você tem que script de todas as coisas que você deseja preservar
capitão Kenpachi
13

Truncar todas as tabelas só funcionará se você não tiver nenhum relacionamento de chave estrangeira entre elas, pois o SQL Server não permitirá que você trunque uma tabela com uma chave estrangeira.

Uma alternativa para isso é determinar as tabelas com chaves estrangeiras e excluí-las primeiro. Em seguida, você pode truncar as tabelas sem chaves estrangeiras posteriormente.

Consulte http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341 e http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 para obter mais detalhes.

marcj
fonte
1
Bom ponto. Não pensei nisso. Talvez eu consiga desativar todas as restrições primeiro e depois reativá-las assim que os dados forem removidos.
Raio
7

Uma opção alternativa que eu gosto de usar com o MSSQL Server Deveploper ou Enterprise é criar uma captura instantânea do banco de dados imediatamente após a criação do esquema vazio. Nesse ponto, você pode continuar restaurando o banco de dados de volta ao instantâneo.

Chris Chilvers
fonte
Infelizmente você perde todos os seus índices do FULLTEXT de cada vez
Chris KL
6

Não faça isso! Realmente, não é uma boa ideia.

Se você souber quais tabelas deseja truncar, crie um procedimento armazenado que as trunque. Você pode corrigir o pedido para evitar problemas com chaves estrangeiras.

Se você realmente deseja truncar todos (para que o BCP possa carregá-los, por exemplo), você seria rápido em descartar o banco de dados e criar um novo a partir do zero, o que traria o benefício adicional de saber exatamente onde você está.

Ben Liddicott
fonte
Boa abordagem alternativa aqui.
Sam
3
o problema com sua abordagem é que a eliminação das tabelas e do banco de dados resultaria na perda de todas as permissões concedidas a diferentes logins e esquemas. Recriar isso será doloroso para bancos de dados grandes com muitas tabelas.
Punit Vora
4

Se você deseja manter os dados em uma tabela específica (ou seja, uma tabela de pesquisa estática) ao excluir / truncar dados em outras tabelas dentro do mesmo banco de dados, precisará de um loop com as exceções nela. Era isso que eu estava procurando quando me deparei com essa pergunta.

sp_MSForEachTable me parece com erros (isto é, comportamento inconsistente com instruções IF), e é provavelmente por isso que não é documentado pela MS.

declare @LastObjectID int = 0
declare @TableName nvarchar(100) = ''
set @LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > @LastObjectID order by [object_id])
while(@LastObjectID is not null)
begin
    set @TableName = (select top 1 [name] from sys.tables where [object_id] = @LastObjectID)

    if(@TableName not in ('Profiles', 'ClientDetails', 'Addresses', 'AgentDetails', 'ChainCodes', 'VendorDetails'))
    begin
        exec('truncate table [' + @TableName + ']')
    end 

    set @LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > @LastObjectID order by [object_id])
end
Chris Smith
fonte
4

A parte mais difícil de truncar todas as tabelas é remover e re-adicionar as restrições de chave estrangeira.

A consulta a seguir cria as instruções drop & create para cada restrição relacionada a cada nome de tabela em @myTempTable. Se você deseja gerá-los para todas as tabelas, use o esquema de informações para reunir esses nomes.

DECLARE @myTempTable TABLE (tableName varchar(200))
INSERT INTO @myTempTable(tableName) VALUES
('TABLE_ONE'),
('TABLE_TWO'),
('TABLE_THREE')


-- DROP FK Contraints
SELECT 'alter table '+quotename(schema_name(ob.schema_id))+
  '.'+quotename(object_name(ob.object_id))+ ' drop constraint ' + quotename(fk.name) 
  FROM sys.objects ob INNER JOIN sys.foreign_keys fk ON fk.parent_object_id = ob.object_id
  WHERE fk.referenced_object_id IN 
      (
         SELECT so.object_id 
         FROM sys.objects so JOIN sys.schemas sc
         ON so.schema_id = sc.schema_id
         WHERE so.name IN (SELECT * FROM @myTempTable)  AND sc.name=N'dbo'  AND type in (N'U'))


 -- CREATE FK Contraints
 SELECT 'ALTER TABLE [PIMSUser].[dbo].[' +cast(c.name as varchar(255)) + '] WITH NOCHECK ADD CONSTRAINT ['+ cast(f.name as varchar(255)) +'] FOREIGN KEY (['+ cast(fc.name as varchar(255)) +'])
      REFERENCES [PIMSUser].[dbo].['+ cast(p.name as varchar(255)) +'] (['+cast(rc.name as varchar(255))+'])'
FROM  sysobjects f
      INNER JOIN sys.sysobjects c ON f.parent_obj = c.id
      INNER JOIN sys.sysreferences r ON f.id = r.constid
      INNER JOIN sys.sysobjects p ON r.rkeyid = p.id
      INNER JOIN sys.syscolumns rc ON r.rkeyid = rc.id and r.rkey1 = rc.colid
      INNER JOIN sys.syscolumns fc ON r.fkeyid = fc.id and r.fkey1 = fc.colid
WHERE 
      f.type = 'F'
      AND
      cast(p.name as varchar(255)) IN (SELECT * FROM @myTempTable)

Depois, copio as instruções para executar - mas com um pouco de esforço de desenvolvimento, você pode usar um cursor para executá-las dinamicamente.

Scott Allen
fonte
3

É muito mais fácil (e possivelmente ainda mais rápido) criar um script para o seu banco de dados, basta soltar e criá-lo a partir do script.

AK
fonte
3

Faça um banco de dados "modelo" vazio, faça um backup completo. Quando você precisar atualizar, basta restaurar usando WITH REPLACE. Rápido, simples, à prova de balas. E se algumas tabelas aqui ou ali precisarem de alguns dados básicos (por exemplo, informações de configuração ou apenas informações básicas que fazem com que seu aplicativo seja executado), eles também lidam com isso.

onupdatecascade
fonte
2

Este é um maneira de fazer isso ... provavelmente há outras 10 que são melhores / mais eficientes, mas parece que isso é feito com pouca frequência, então aqui vai ...

obtenha uma lista dos tablese sysobjects, em seguida, faça um loop sobre aqueles com um cursor, chamando sp_execsql('truncate table ' + @table_name)cada um iteration.

Ben Scheirman
fonte
post adicionado com sql que faz exatamente isso :) uma vez que era isso que eu estava procurando também.
Chris Smith
1

Execute a seção comentada uma vez, preencha a tabela _TruncateList com as tabelas que você deseja truncar e, em seguida, execute o restante do script. A tabela _ScriptLog precisará ser limpa com o tempo, se você fizer muito isso.

Você pode modificar isso se quiser fazer todas as tabelas, basta colocar o nome SELECT em #TruncateList FROM sys.tables. No entanto, você geralmente não deseja fazer todos eles.

Além disso, isso afetará todas as chaves estrangeiras no banco de dados, e você também poderá modificá-las se for muito forte para o seu aplicativo. Não é para os meus propósitos.

/*
CREATE TABLE _ScriptLog 
(
    ID Int NOT NULL Identity(1,1)
    , DateAdded DateTime2 NOT NULL DEFAULT GetDate()
    , Script NVarChar(4000) NOT NULL
)

CREATE UNIQUE CLUSTERED INDEX IX_ScriptLog_DateAdded_ID_U_C ON _ScriptLog
(
    DateAdded
    , ID
)

CREATE TABLE _TruncateList
(
    TableName SysName PRIMARY KEY
)
*/
IF OBJECT_ID('TempDB..#DropFK') IS NOT NULL BEGIN
    DROP TABLE #DropFK
END

IF OBJECT_ID('TempDB..#TruncateList') IS NOT NULL BEGIN
    DROP TABLE #TruncateList
END

IF OBJECT_ID('TempDB..#CreateFK') IS NOT NULL BEGIN
    DROP TABLE #CreateFK
END

SELECT Scripts = 'ALTER TABLE ' + '[' + OBJECT_NAME(f.parent_object_id)+ ']'+
' DROP  CONSTRAINT ' + '[' + f.name  + ']'
INTO #DropFK
FROM .sys.foreign_keys AS f
INNER JOIN .sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id

SELECT TableName
INTO #TruncateList
FROM _TruncateList

SELECT Scripts = 'ALTER TABLE ' + const.parent_obj + '
    ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
            ' + const.parent_col_csv + '
            ) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ')
'
INTO #CreateFK
FROM (
    SELECT QUOTENAME(fk.NAME) AS [const_name]
        ,QUOTENAME(schParent.NAME) + '.' + QUOTENAME(OBJECT_name(fkc.parent_object_id)) AS [parent_obj]
        ,STUFF((
                SELECT ',' + QUOTENAME(COL_NAME(fcP.parent_object_id, fcp.parent_column_id))
                FROM sys.foreign_key_columns AS fcP
                WHERE fcp.constraint_object_id = fk.object_id
                FOR XML path('')
                ), 1, 1, '') AS [parent_col_csv]
        ,QUOTENAME(schRef.NAME) + '.' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)) AS [ref_obj]
        ,STUFF((
                SELECT ',' + QUOTENAME(COL_NAME(fcR.referenced_object_id, fcR.referenced_column_id))
                FROM sys.foreign_key_columns AS fcR
                WHERE fcR.constraint_object_id = fk.object_id
                FOR XML path('')
                ), 1, 1, '') AS [ref_col_csv]
    FROM sys.foreign_key_columns AS fkc
    INNER JOIN sys.foreign_keys AS fk ON fk.object_id = fkc.constraint_object_id
    INNER JOIN sys.objects AS oParent ON oParent.object_id = fkc.parent_object_id
    INNER JOIN sys.schemas AS schParent ON schParent.schema_id = oParent.schema_id
    INNER JOIN sys.objects AS oRef ON oRef.object_id = fkc.referenced_object_id
    INNER JOIN sys.schemas AS schRef ON schRef.schema_id = oRef.schema_id
    GROUP BY fkc.parent_object_id
        ,fkc.referenced_object_id
        ,fk.NAME
        ,fk.object_id
        ,schParent.NAME
        ,schRef.NAME
    ) AS const
ORDER BY const.const_name

INSERT INTO _ScriptLog (Script)
SELECT Scripts
FROM #CreateFK

DECLARE @Cmd NVarChar(4000)
    , @TableName SysName

WHILE 0 < (SELECT Count(1) FROM #DropFK) BEGIN
    SELECT TOP 1 @Cmd = Scripts 
    FROM #DropFK

    EXEC (@Cmd)

    DELETE #DropFK WHERE Scripts = @Cmd
END

WHILE 0 < (SELECT Count(1) FROM #TruncateList) BEGIN
    SELECT TOP 1 @Cmd = N'TRUNCATE TABLE ' +  TableName
        , @TableName = TableName
    FROM #TruncateList

    EXEC (@Cmd)

    DELETE #TruncateList WHERE TableName = @TableName
END

WHILE 0 < (SELECT Count(1) FROM #CreateFK) BEGIN
    SELECT TOP 1 @Cmd = Scripts 
    FROM #CreateFK

    EXEC (@Cmd)

    DELETE #CreateFK WHERE Scripts = @Cmd
END
Steve Hood
fonte
0

Não vejo por que limpar dados seria melhor que um script para descartar e recriar cada tabela.

Isso ou mantenha um backup do seu banco de dados vazio e restaure-o sobre o antigo

Brian Spencer
fonte
2
O motivo é a sobrecarga de descartar e recriar os arquivos em disco do banco de dados, os logs etc. é muito lenta. Pense em limpar o banco de dados 1.000 vezes durante uma execução de teste de unidade decente.
22412 Chris KL
0

Antes de truncar as tabelas, você deve remover todas as chaves estrangeiras. Use este script para gerar scripts finais para eliminar e recriar todas as chaves estrangeiras no banco de dados. Defina a variável @action como 'CREATE' ou 'DROP'.

Edward Weinert
fonte
0

selecione 'excluir de' + TABLE_NAME de INFORMATION_SCHEMA.TABLES em que TABLE_TYPE = 'BASE TABLE'

de onde vem o resultado.

Copie e cole na janela de consulta e execute o comando

Somendra Tiwari
fonte
0

É um pouco tarde, mas pode ajudar alguém. Às vezes, criei um procedimento que faz o seguinte usando o T-SQL:

  1. Armazenar todas as restrições em uma tabela temporária
  2. Eliminar todas as restrições
  3. Truncar todas as tabelas, com exceção de algumas tabelas, que não precisam de truncamento
  4. Recrie todas as restrições.

Eu listei no meu blog aqui

Mohit
fonte