Existe uma maneira de gerar um script de criação a partir de uma tabela existente puramente no 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 retorne uma string que contém o script de criação para a tabela especificada?
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, as mesmas tabelas, índices e assim por diante. Eles foram criados como parte de uma instalação de software de terceiros. Preciso ter uma maneira de trabalhar com eles para poder agregar dados deles de maneira ad-hoc. Pessoas legais do dba.se já me ajudaram aqui Como criar um gatilho em um banco de dados diferente?
Atualmente, preciso encontrar uma maneira de fazer uma seleção em 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 é usada e IDENTITY_INSERT está ativado.
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 em 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ê precisará especificar novamente a lista de colunas, que seria diferente dependendo da tabela que você consultar.
Então, eu estava pensando que se eu pudesse obter o script create table no meu código T-SQL, 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 conseguir o que eu quero?
fonte
Não é possível no T-SQL gerar um script de criação completo de uma tabela. Pelo menos não há construção no caminho. você sempre pode escrever seu próprio "gerador" passando as informações
sys.columns
.Mas no seu caso, você não precisa obter o script de criação completo. Tudo que você precisa é impedir a
SELECT INTO
cópia da propriedade de identidade. A maneira mais fácil de fazer isso é adicionar um cálculo a essa coluna. Então, ao invés 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:Consulta 2 :
Resultados :
Com um pouco de truque XML, podemos concatenar tudo isso juntos para obter a lista completa das colunas:
Consulta 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 fica fora de escopo quando a instrução sql dinâmica terminar. Portanto, você deve espremer todo o seu código na mesma string SQL dinâmica ou usar uma tabela real. Se você precisar executar vários desses scripts / procedimentos ao mesmo tempo, precisará de um nome de tabela aleatório, caso contrário, eles entrarão em conflito. Algo como
QUOTENAME(N'temp_'+CAST(NEWID() AS NVARCHAR(40))
deve dar 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. Porém, dependendo do tamanho da tabela que pode ser mais rápido ou mais lento, você deve testá-lo. Se você seguir esse caminho, eu colocaria essas visualizações em um banco de dados separado.
fonte
Há um bom script para conseguir isso no artigo SQLServerCentral:
A versão mais recente atual 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.
Nota de direitos autorais:
fonte
Você pode gerar uma
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
fonte