Existe uma maneira de gerar um script de criação a partir de uma tabela existente puramente em T-SQL (ou seja, sem usar o SMO, pois o T-SQL não tem acesso ao SMO). Digamos que um procedimento armazenado que recebe um nome de tabela e retorna uma string que contém o script de criação para a tabela fornecida?
Agora deixe-me descrever a situação que estou enfrentando, pois pode haver uma maneira diferente de abordar isso. Eu tenho uma instância com várias dezenas de bancos de dados. Todos esses bancos de dados têm o mesmo esquema, todas as mesmas tabelas, índice e assim por diante. Eles foram criados como parte de uma instalação de software de terceiros. Eu preciso ter uma maneira de trabalhar com eles para que eu possa agregar dados deles de maneira ad-hoc. Boas pessoas do dba.se já me ajudaram aqui Como criar uma trigger em um banco de dados diferente?
Atualmente preciso encontrar uma maneira de fazer uma seleção de uma tabela em todos os bancos de dados. Gravei todos os nomes de banco de dados em uma tabela chamada Databasees
e escrevi o seguinte script para executar uma instrução select em todos eles:
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp
select * into #tmp from Database1.dbo.Table1 where 1=0
DECLARE @statement nvarchar(max) =
N'insert into #tmp select * from Table1 where Column1=0 and Cloumn2 =1'
DECLARE @LastDatabaseID INT
SET @LastDatabaseID = 0
DECLARE @DatabaseNameToHandle varchar(60)
DECLARE @DatabaseIDToHandle int
SELECT TOP 1 @DatabaseNameToHandle = Name,
@DatabaseIDToHandle = Database_Ref_No
FROM Databasees
WHERE Database_Ref_No > @LastDatabaseID
ORDER BY Database_Ref_No
WHILE @DatabaseIDToHandle IS NOT NULL
BEGIN
DECLARE @sql NVARCHAR(MAX) = QUOTENAME(@DatabaseNameToHandle) + '.dbo.sp_executesql'
EXEC @sql @statement
SET @LastDatabaseID = @DatabaseIDToHandle
SET @DatabaseIDToHandle = NULL
SELECT TOP 1 @DatabaseNameToHandle = Name,
@DatabaseIDToHandle = Database_Ref_No
FROM Databasees
WHERE Database_Ref_No > @LastDatabaseID
ORDER BY Database_Ref_No
END
select * from #tmp
DROP TABLE #tmp
No entanto, o script acima falha com a seguinte mensagem:
Um valor explícito para a coluna de identidade na tabela '#tmp' só pode ser especificado quando uma lista de colunas for usada e IDENTITY_INSERT estiver ON.
Adicionando isso:
SET IDENTITY_INSERT #tmp ON
não ajuda, pois não consigo especificar a lista de colunas e mantê-la genérica.
No SQL, não há como desativar a identidade de uma determinada tabela. Você só pode soltar uma coluna e adicionar uma coluna, o que obviamente altera a ordem das colunas. E se a ordem das colunas mudar, você, novamente, precisa especificar a lista de colunas, que seria diferente dependendo da tabela consultada.
Então, eu estava pensando se eu pudesse obter o script de criação de tabela no meu código T-SQL, eu poderia manipulá-lo com expressões de manipulação de string para remover a coluna de identidade e também adicionar uma coluna para o nome do banco de dados ao conjunto de resultados.
Alguém pode pensar em uma maneira relativamente fácil de alcançar o que eu quero?
Em 2007, pedi uma maneira fácil de gerar um
CREATE TABLE
script via T-SQL em vez de usar a interface do usuário ou SMO. Fui sumariamente rejeitado .No entanto, o SQL Server 2012 torna isso muito fácil. Vamos fingir que temos uma tabela com o mesmo esquema em vários bancos de dados, por exemplo
dbo.whatcha
:O script a seguir usa a nova
sys.dm_exec_describe_first_results_set
função de gerenciamento dinâmico para recuperar os tipos de dados apropriados para cada uma das colunas (e ignorando aIDENTITY
propriedade). Ele cria a tabela #tmp que você precisa, insere de cada um dos bancos de dados em sua lista e seleciona de #tmp, tudo dentro de um único lote SQL dinâmico e sem usar umWHILE
loop (isso não o torna melhor, apenas mais simples de olhar e permite que você ignoreDatabase_Ref_No
completamente :-)).PRINT
A saída resultante :Quando você estiver confiante de que está fazendo o que você espera, apenas remova o comentário do arquivo
EXEC
.(Isso confia em você que o esquema é o mesmo; ele não valida que uma ou mais das tabelas foi alterada e pode falhar como resultado.)
Não é possível no T-SQL gerar um script de criação completo de uma tabela. Pelo menos não há nenhuma construção no caminho. você sempre pode escrever seu próprio "gerador" passando pelas informações
sys.columns
.Mas no seu caso você não precisa obter o script de criação completo. Tudo o que você precisa é impedir que a
SELECT INTO
propriedade de identidade seja copiada. A maneira mais fácil de fazer isso é adicionar um cálculo a essa coluna. Então, em vez devocê precisa escrever
Para gerar esta instrução, você pode usar novamente sys.columns como neste SQL Fiddle
Configuração do esquema do MS SQL Server 2008 :
As duas colunas que precisamos são
name
eis_identity
: Consulta 1 :Resultados :
Com isso podemos usar uma
CASE
instrução para gerar cada coluna para a lista de colunas:Pergunta 2 :
Resultados :
Com um pequeno truque de XML, podemos concatenar tudo isso para obter a lista completa de colunas:
Pergunta 3 :
Resultados :
Lembre-se de que você não pode criar uma tabela #temp usando SQL dinâmico e usá-la fora dessa instrução, pois a tabela #temp sai do escopo quando sua instrução sql dinâmica termina. Portanto, você precisa espremer todo o seu código na mesma string SQL dinâmica ou usar uma tabela real. Se você precisa executar vários desses scripts/procedimentos ao mesmo tempo, você precisa de um nome de tabela aleatório, caso contrário, eles irão pisar um no outro. Algo como
QUOTENAME(N'temp_'+CAST(NEWID() AS NVARCHAR(40))
deve fazer um nome bom o suficiente.Em vez de copiar todos os dados, você também pode usar uma técnica semelhante para gerar automaticamente uma exibição para cada tabela que une todas as encarnações dessa tabela em todos os bancos de dados. Dependendo do tamanho da tabela, no entanto, isso pode ser mais rápido ou mais lento, então você deve testá-lo. Se você seguir esse caminho, eu colocaria essas visualizações em um banco de dados separado.
Existe um bom script para conseguir isso no artigo SQLServerCentral:
A versão mais recente do script também está disponível como texto aqui (stormrage.com).
Eu gostaria que houvesse uma maneira de incluir todo o script aqui, porque funciona para mim. O script é muito longo para colar aqui.
Aviso de direitos autorais:
Você pode gerar um rascunho
CREATE TABLE
usando SQL dinâmico a partir dos dados emINFORMATION_SCHEMA.COLUMNS
.Se você precisar adicionar restrições, etc., precisará adicionar informações de algumas das outras
INFORMATION_SCHEMA
visualizações.Documentação da Microsoft