SQL Server: copie procedimientos almacenados de una base de datos a otra

86

Soy nuevo en SQL y lo que tenía que hacer era combinar 2 bases de datos .mdf en una. Lo hice usando SQL Server 2008 Manager - Tareas> Importar / Exportar tablas. Las tablas y vistas se copiaron correctamente, pero no hay procedimientos almacenados en la nueva base de datos. ¿Hay alguna manera de hacerlo?

Roble
fuente
1
Si desea copiarlos mediante programación, comience aquí: stackoverflow.com/a/6124487/138938
Jon Crowell

Respuestas:

137
  • Haga clic derecho en la base de datos
  • Tareas
  • Generar guiones
  • Seleccione los objetos que desea escribir
  • Script a archivo
  • Ejecute scripts generados contra la base de datos de destino
Jaimal Chohan
fuente
Hola, gracias por la rápida respuesta. ¿Puede explicar cómo utilizar el script contra la base de datos de destino? Soy nuevo en esto.
Oak
1
@BarryKaye ¿Qué pasa si tiene 30-40 procedimientos almacenados? ¿No sería un poco lento hacer clic derecho?
rvphx
@Oak Abra el archivo de script de generación en SQL Management Studio. Cambie la conexión a su nueva base de datos. Cambie la línea en la parte superior del archivo donde dice 'Use DatabaseName' en su base de datos y ejecute.
Jaimal Chohan
Guau. ¡Ahora pensé que yo era el único al que le gustaba el enfoque basado en GUI!
rvphx
10
@RajivVarma: realiza esta tarea una vez para la base de datos, ¡no para cada SP! Si marca la casilla de verificación de nivel superior junto a "Procedimientos almacenados", los selecciona todos juntos: 1 clic.
Barry Kaye
19

Este código copia todos los procedimientos almacenados en la base de datos maestra en la base de datos de destino, puede copiar solo los procedimientos que desee filtrando la consulta por el nombre del procedimiento.

@sql se define como nvarchar (max), @Name es la base de datos de destino

DECLARE c CURSOR FOR 
   SELECT Definition
   FROM [ResiDazeMaster].[sys].[procedures] p
   INNER JOIN [ResiDazeMaster].sys.sql_modules m ON p.object_id = m.object_id

OPEN c

FETCH NEXT FROM c INTO @sql

WHILE @@FETCH_STATUS = 0 
BEGIN
   SET @sql = REPLACE(@sql,'''','''''')
   SET @sql = 'USE [' + @Name + ']; EXEC(''' + @sql + ''')'

   EXEC(@sql)

   FETCH NEXT FROM c INTO @sql
END             

CLOSE c
DEALLOCATE c
ShaQue
fuente
¡Gracias! ... En los comentarios, pero no declarados en el código son @sql& @Name:DECLARE @sql NVARCHAR(MAX); DECLARE @Name NVARCHAR(32);
datalifenyc
¿Hay alguna forma de hacer esto mismo en diferentes servidores? ¿Del servidor A al servidor B?
Rajaram1991
5

Tarde uno pero da más detalles que podrían ser útiles ...

Aquí hay una lista de cosas que puede hacer con ventajas y desventajas

Genere scripts usando SSMS

  • Ventajas: extremadamente fácil de usar y compatible de forma predeterminada
  • Contras: scripts pueden no estar en el orden de ejecución correcto y es posible que obtenga errores si el procedimiento almacenado ya existe en la base de datos secundaria. Asegúrese de revisar el script antes de ejecutarlo.

Herramientas de terceros

  • Ventajas: herramientas como ApexSQL Diff (esto es lo que yo uso, pero hay muchas otras como herramientas de Red Gate o Dev Art) compararán dos bases de datos con un solo clic y generarán un script que puede ejecutar de inmediato
  • Contras: estos no son gratuitos (la mayoría de los proveedores tienen una versión de prueba completamente funcional)

Vistas del sistema

  • Pros: puede ver fácilmente qué procedimientos almacenados existen en el servidor secundario y solo generar los que no tiene.
  • Contras: Requiere un poco más de conocimiento SQL

A continuación se explica cómo obtener una lista de todos los procedimientos en alguna base de datos que no existen en otra base de datos

select *
from DB1.sys.procedures P
where P.name not in 
 (select name from DB2.sys.procedures P2)
LarryB
fuente
5

Originalmente encontré esta publicación buscando una solución para copiar procedimientos almacenados desde mi base de datos de producción remota a mi base de datos de desarrollo local. Después de utilizar con éxito el enfoque sugerido en este hilo, me di cuenta de que me volvía cada vez más perezoso (o ingenioso, lo que prefieras) y quería que esto se automatizara. Encontré este enlace , que resultó ser muy útil (gracias vincpa), y lo extendí, dando como resultado el siguiente archivo (schema_backup.ps1):

$server             = "servername"
$database           = "databaseName"
$output_path        = "D:\prod_schema_backup"
$login = "username"
$password = "password"

$schema             = "dbo"
$table_path         = "$output_path\table\"
$storedProcs_path   = "$output_path\stp\"
$views_path         = "$output_path\view\"
$udfs_path          = "$output_path\udf\"
$textCatalog_path   = "$output_path\fulltextcat\"
$udtts_path         = "$output_path\udtt\"

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo")  | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended")  | out-null
$srvConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$srvConn.ServerInstance = $server
$srvConn.LoginSecure = $false
$srvConn.Login = $login
$srvConn.Password = $password
$srv        = New-Object Microsoft.SqlServer.Management.SMO.Server($srvConn)
$db         = New-Object ("Microsoft.SqlServer.Management.SMO.Database")
$tbl        = New-Object ("Microsoft.SqlServer.Management.SMO.Table")
$scripter   = New-Object Microsoft.SqlServer.Management.SMO.Scripter($srvConn)

# Get the database and table objects
$db = $srv.Databases[$database]

$tbl            = $db.tables | Where-object { $_.schema -eq $schema  -and -not $_.IsSystemObject } 
$storedProcs    = $db.StoredProcedures | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject } 
$views          = $db.Views | Where-object { $_.schema -eq $schema } 
$udfs           = $db.UserDefinedFunctions | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject } 
$catlog         = $db.FullTextCatalogs
$udtts          = $db.UserDefinedTableTypes | Where-object { $_.schema -eq $schema } 

# Set scripter options to ensure only data is scripted
$scripter.Options.ScriptSchema  = $true;
$scripter.Options.ScriptData    = $false;

#Exclude GOs after every line
$scripter.Options.NoCommandTerminator   = $false;
$scripter.Options.ToFileOnly            = $true
$scripter.Options.AllowSystemObjects    = $false
$scripter.Options.Permissions           = $true
$scripter.Options.DriAllConstraints     = $true
$scripter.Options.SchemaQualify         = $true
$scripter.Options.AnsiFile              = $true

$scripter.Options.SchemaQualifyForeignKeysReferences = $true

$scripter.Options.Indexes               = $true
$scripter.Options.DriIndexes            = $true
$scripter.Options.DriClustered          = $true
$scripter.Options.DriNonClustered       = $true
$scripter.Options.NonClusteredIndexes   = $true
$scripter.Options.ClusteredIndexes      = $true
$scripter.Options.FullTextIndexes       = $true

$scripter.Options.EnforceScriptingOptions   = $true

function CopyObjectsToFiles($objects, $outDir) {
    #clear out before 
    Remove-Item $outDir* -Force -Recurse
    if (-not (Test-Path $outDir)) {
        [System.IO.Directory]::CreateDirectory($outDir)
    }   

    foreach ($o in $objects) { 

        if ($o -ne $null) {

            $schemaPrefix = ""

            if ($o.Schema -ne $null -and $o.Schema -ne "") {
                $schemaPrefix = $o.Schema + "."
            }

            #removed the next line so I can use the filename to drop the stored proc 
            #on the destination and recreate it
            #$scripter.Options.FileName = $outDir + $schemaPrefix + $o.Name + ".sql"
            $scripter.Options.FileName = $outDir + $schemaPrefix + $o.Name
            Write-Host "Writing " $scripter.Options.FileName
            $scripter.EnumScript($o)
        }
    }
}

# Output the scripts
CopyObjectsToFiles $tbl $table_path
CopyObjectsToFiles $storedProcs $storedProcs_path
CopyObjectsToFiles $views $views_path
CopyObjectsToFiles $catlog $textCatalog_path
CopyObjectsToFiles $udtts $udtts_path
CopyObjectsToFiles $udfs $udfs_path

Write-Host "Finished at" (Get-Date)
$srv.ConnectionContext.Disconnect()

Tengo un archivo .bat que llama a esto y se llama desde el Programador de tareas. Después de la llamada al archivo Powershell, tengo:

for /f %f in ('dir /b d:\prod_schema_backup\stp\') do sqlcmd /S localhost /d dest_db /Q "DROP PROCEDURE %f"

Esa línea pasará por el directorio y eliminará los procedimientos que va a recrear. Si este no fuera un entorno de desarrollo, no me gustaría descartar procedimientos mediante programación de esta manera. Luego cambio el nombre de todos los archivos de procedimiento almacenado para tener .sql:

powershell Dir d:\prod_schema_backup\stp\ | Rename-Item -NewName { $_.name + ".sql" }

Y luego ejecuta:

for /f %f in ('dir /b d:\prod_schema_backup\stp\') do sqlcmd /S localhost /d dest_db /E /i "%f".sql

Y eso itera a través de todos los archivos .sql y recrea los procedimientos almacenados. Espero que alguna parte de esto resulte útil para alguien.

vandsh
fuente
Me gusta esto. Tengo que escribir un proceso para archivar fragmentos de una base de datos de producciones un año a la vez. No quiero tener archivos SQL colgados que probablemente no se actualizarán a medida que se desarrolle el esquema, así que estoy adaptando esto para crear una base de datos vacía basada en un destino sin el paso intermedio de escribir archivos en el disco (más limpiar). Creo que esta es probablemente la mejor y más reutilizable respuesta a esta pregunta, ¡felicitaciones, señor!
Steve Pettifer
3

Puede utilizar la función "Generar secuencias de comandos ..." de SSMS para generar secuencias de comandos para lo que necesite transferir. Haga clic con el botón derecho en la base de datos de origen en SSMS, seleccione "Generar secuencias de comandos ..." y siga el asistente. Luego, ejecute su script resultante que ahora contendrá las instrucciones de creación del procedimiento almacenado.

vector azul
fuente
3

utilizar

select * from sys.procedures

para mostrar todos sus procedimientos;

sp_helptext @objname = 'Procedure_name'

para obtener el código

y su creatividad para construir algo para recorrerlos todos y generar el código de exportación :)

Diego
fuente
3

Puede generar un script de los procesos almacenados como se muestra en otras respuestas. Una vez que se ha generado el script, puede usarlo sqlcmdpara ejecutarlo contra la base de datos de destino como

sqlcmd -S <server name> -U <user name> -d <DB name> -i <script file> -o <output log file> 
Rahul
fuente
0

En Mgmt Studio, haga clic con el botón derecho en su base de datos original, luego en Tareas y luego en Generar scripts ... - siga el asistente.

Barry Kaye
fuente
0

SELECCIONAR definición + char (13) + 'IR' DE MyDatabase.sys.sql_modules s INNER JOIN MyDatabase.sys.procedures p ON [s]. [Object_id] = [p]. [Object_id] DONDE p.name LIKE 'Something% '"queryout" c: \ SP_scripts.sql -S MyInstance -T -t -w

obtener el sp y ejecutarlo

ShaQue
fuente
Esta es una solución muy buena, pero 1) debe señalar que se necesita salida de texto o archivo (no muestre los resultados en la cuadrícula, o perderá caracteres EOL) y 2) parece que hay un límite de 8k para la salida de texto en SQL Server Management Studio.
DAB
0

Otra opción es transferir procedimientos almacenados mediante SQL Server Integration Services (SSIS) . Hay una tarea llamada Tarea Transferir objetos de SQL Server . Puede utilizar la tarea para transferir los siguientes elementos:

  • Mesas
  • Puntos de vista
  • Procedimientos almacenados
  • Funciones definidas por el usuario
  • Defaults
  • Tipos de datos definidos por el usuario
  • Funciones de partición
  • Esquemas de partición
  • Esquemas
  • Ensambles
  • Agregados definidos por el usuario
  • Tipos definidos por el usuario
  • Colección de esquemas XML

Es un tutorial gráfico para la tarea Transferir objetos de SQL Server.

Abdollah
fuente