¿Hay alguna manera de generar un script de creación a partir de una tabla existente únicamente en T-SQL (es decir, sin usar SMO, ya que T-SQL no tiene acceso a SMO)? Digamos un procedimiento almacenado que recibe un nombre de tabla y devuelve una cadena que contiene el script de creación para la tabla dada.
Ahora permítanme describir la situación que estoy enfrentando, ya que puede haber una forma diferente de abordar esto. Tengo una instancia con varias docenas de bases de datos. Todas estas bases de datos tienen el mismo esquema, todas las mismas tablas, índices, etc. Fueron creados como parte de una instalación de software de terceros. Necesito tener una manera de trabajar con ellos para poder agregar datos de ellos de manera ad-hoc. Gente amable en dba.se ya me ha ayudado aquí ¿Cómo crear un activador en una base de datos diferente?
Actualmente necesito encontrar una manera de hacer una selección de una tabla en todas las bases de datos. Grabé todos los nombres de las bases de datos en una tabla llamada Databasees
y escribí el siguiente script para ejecutar una instrucción select en todos ellos:
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
Sin embargo, el script anterior falla con el siguiente mensaje:
Un valor explícito para la columna de identidad en la tabla '#tmp' solo se puede especificar cuando se utiliza una lista de columnas y IDENTITY_INSERT está ACTIVADO.
Agregando esto:
SET IDENTITY_INSERT #tmp ON
no ayuda, ya que no puedo especificar la lista de columnas y mantenerla genérica.
En SQL no hay forma de desactivar la identidad en una tabla determinada. Solo puede soltar una columna y agregar una columna que, obviamente, cambia el orden de las columnas. Y si el orden de las columnas cambia, usted, nuevamente, necesita especificar la lista de columnas, eso sería diferente dependiendo de la tabla que consulte.
Entonces pensé que si podía obtener el script de creación de tabla en mi código T-SQL, podría manipularlo con expresiones de manipulación de cadenas para eliminar la columna de identidad y también agregar una columna para el nombre de la Base de datos al conjunto de resultados.
¿Alguien puede pensar en una forma relativamente fácil de lograr lo que quiero?
fuente
No es posible que int T-SQL genere un script de creación completo de una tabla. Al menos no hay forma de construir. siempre puedes escribir tu propio "generador" revisando la información
sys.columns
.Pero en su caso no necesita obtener el script de creación completo. Todo lo que necesita es evitar que
SELECT INTO
copie la propiedad de identidad. La forma más fácil de hacerlo es agregar un cálculo a esa columna. Entonces en lugar denecesitas escribir
Para generar esta declaración, puede usar nuevamente sys.columns como en este Fiddle de SQL
Configuración del esquema de MS SQL Server 2008 :
Las dos columnas que necesitamos son
name
yis_identity
: Consulta 1 :Resultados :
Con eso podemos usar una
CASE
declaración para generar cada columna para la lista de columnas:Consulta 2 :
Resultados :
Con un pequeño truco XML podemos concatenar todo esto para obtener la lista completa de columnas:
Consulta 3 :
Resultados :
Tenga en cuenta que no puede crear una tabla #temp usando SQL dinámico y usarla fuera de esa declaración ya que la tabla #temp queda fuera de alcance una vez que finalice su declaración sql dinámica. Por lo tanto, debe exprimir todo su código en la misma cadena dinámica de SQL o usar una tabla real. Si necesita poder ejecutar múltiples de estos scripts / procedimientos al mismo tiempo, necesita un nombre de tabla aleatorio, de lo contrario, se pisarán entre sí. Algo así
QUOTENAME(N'temp_'+CAST(NEWID() AS NVARCHAR(40))
debería ser un nombre lo suficientemente bueno.En lugar de copiar todos los datos, también puede usar una técnica similar para generar automáticamente una vista para cada tabla que une todas las encarnaciones de esa tabla en todas las bases de datos. Sin embargo, según el tamaño de la tabla, puede ser más rápido o más lento, por lo que debe probarlo. Si sigue esta ruta, pondría esas vistas en una base de datos separada.
fuente
Hay un buen script para lograr esto en el artículo SQLServerCentral:
La última versión actual del script también está disponible como texto aquí (stormrage.com).
Desearía que hubiera una manera de incluir todo el guión aquí, porque funciona para mí. El guión es demasiado largo para pegarlo aquí.
Aviso de copyright:
fuente
Puede generar un bruto
CREATE TABLE
utilizando SQL dinámico a partir de los datos enINFORMATION_SCHEMA.COLUMNS
.Si necesita agregar restricciones, etc., deberá agregar información de algunas de las otras
INFORMATION_SCHEMA
vistas.Documentación de Microsoft
fuente