简体   繁体   中英

Database relocation, Detach/attach database, MS-SQL-Server-Management-Studio(2012)

In the next week we want to relocate our database from one server to another one. On http://msdn.microsoft.com/en-us/library/ms187858%28v=sql.110%29.aspx
I read about detaching the database from the old location and attach it to the new location. The problem is, that I don't have access to the file system of the server, I don't even know where exactly the server is physically located^^
Is there a way to relocate a database from one Server to another without the need to access the file system of the old Server?

You could use the Import/Export tool in SQL Server to copy the data directly which will create a new database in the destination location. The good thing about this is the new DB will work as you might expect since it is created from scratch on the target server, but that also means that you might have old, deprecated syntax in your stored procs or functions or whatever which won't work unless you lower the compatibility level (although that shouldn't be hard). also be aware of any possible collation conflicts (your old server might have SQL_Latin1_General_CP1_CI_AS and the new one might be Latin1_General_CI_AS which can cause equality operations to fail amongst other things).

In addition, if you have a big database then it'll take a long time, but I can't think of any other method off the of of my head which doesn't require some level of access to the file system as you'd still need to get to the file system to take a copy of a backup, or if using a UNC path for the backup the source server would need to be able to write to that location and you'd need to be able to access it afterwards. If anyone else can think of one I'd be interested because it would be a useful bit of knowledge to have tucked away.

Edit:

Should also have mentioned the use of Powershell and SMO - it's not really any different to using the Import/Export wizard but it does allow you to fine tune things. The following is a PS script I have been using to create a copy of a DB (schema only) on a different server to the original but with certain facets missing (NCIs, FKs Indeitites etc) as the copy was destined to be read-only. You could easily extend it to copy the data as well.

param (
    [string]$sourceServerName = $(throw "Source server name is required."),
    [string]$destServerName = $(throw "Destination server is required."),
    [string]$sourceDBName = $(throw "Source database name is required."),
    [string]$destDBName = $(throw "Destination database name is required"),
    [string]$schema = "dbo"
 )

# Add an error trap so that at the end of the script we can see if we recorded any non-fatal errors and if so then throw
# an error and return 1 so that the SQL job recognises there's been an error.
trap 
{ 
  write-output $_ 
  exit 1 
}

# Append year to destination DB name if it isn't already on the end.
$year = (Get-Date).AddYears(-6).Year

if (-Not $destDBName.EndsWith($year)) {
    $destDBName+=$year
}

# Load assemblies.
[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

# Set up source connection.
$sourceSrvConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$sourceSrvConn.ServerInstance = $sourceServerName
$sourceSrvConn.LoginSecure = $false
$sourceSrvConn.Login = "MyLogin"
$sourceSrvConn.Password = "xxx"

# Set up destination connection.
$destSrvConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$destSrvConn.ServerInstance = $destServerName
$destSrvConn.LoginSecure = $false
$destSrvConn.Login = "MyLogin"
$destSrvConn.Password = "xxx"


$sourceSrv  = New-Object Microsoft.SqlServer.Management.SMO.Server($sourceSrvConn)
$sourceDb   = New-Object ("Microsoft.SqlServer.Management.SMO.Database")
$destSrv  = New-Object Microsoft.SqlServer.Management.SMO.Server($destSrvConn)
$destDb   = New-Object ("Microsoft.SqlServer.Management.SMO.Database")
$tbl        = New-Object ("Microsoft.SqlServer.Management.SMO.Table")
$scripter   = New-Object Microsoft.SqlServer.Management.SMO.Scripter($sourceSrvConn)

# Get the database objects
$sourceDb = $sourceSrv.Databases[$sourceDbName]
$destDb = $destSrv.Databases[$destDbName]

# Test to see databases exist. Not as easy to test for servers - if you got those wrong then this will fail and throw an error
# so it's down to the user to check their values carefully.
if ($sourceDb -eq $null) {throw "Database '" + $sourceDbName + "' does not exist on server '" + $sourceServerName + "'"}
if ($destDb -eq $null) {throw "Database '" + $destDbName + "' does not exist on server '" + $destServerName + "'"}

# Get source objects.
$tbl            = $sourceDb.tables | Where-object { $_.schema -eq $schema  -and -not $_.IsSystemObject } 
$storedProcs    = $sourceDb.StoredProcedures | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject } 
$views          = $sourceDb.Views | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject } 
$udfs           = $sourceDb.UserDefinedFunctions | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject } 
$catalogs       = $sourceDb.FullTextCatalogs
$udtts          = $sourceDb.UserDefinedTableTypes | Where-object { $_.schema -eq $schema -and -not $_.IsSystemObject } 
$assemblies     = $sourceDb.Assemblies | Where-object { -not $_.IsSystemObject } 


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

#Exclude GOs after every line
$scripter.Options.NoCommandTerminator   = $false;
$scripter.Options.ToFileOnly            = $false
$scripter.Options.AllowSystemObjects    = $false
$scripter.Options.Permissions           = $true
$scripter.Options.DriForeignKeys        = $false
$scripter.Options.SchemaQualify         = $true
$scripter.Options.AnsiFile              = $true
$scripter.Options.Indexes               = $false
$scripter.Options.DriIndexes            = $false
$scripter.Options.DriClustered          = $true
$scripter.Options.DriNonClustered       = $false
$scripter.Options.NonClusteredIndexes   = $false
$scripter.Options.ClusteredIndexes      = $true
$scripter.Options.FullTextIndexes       = $true
$scripter.Options.NoIdentities          = $true
$scripter.Options.DriPrimaryKey         = $true

$scripter.Options.EnforceScriptingOptions   = $true


$pattern = "(\b" + $sourceDBName + "\b)"
$errors = 0

function CopyObjectsToDestination($objects) {

    foreach ($o in $objects) { 

        if ($o -ne $null) {
            try {
                $script = $scripter.Script($o)

                $script = $script -replace $pattern, $destDBName
                $destDb.ExecuteNonQuery($script)
            } catch {
                #Make sure any errors are logged by the SQL job.
                $ex = $_.Exception
                $message = $o.Name + " " + (Get-Date)
                $message += "`r`n"
                #$message += $ex.message
                $ex = $ex.InnerException

                while ($ex.InnerException) {
                    $message += "`n$ex.InnerException.message"
                    $ex = $ex.InnerException

                }
                #Write-Error $o.Name 
                Write-Error $message    # Write to caller. SQL Agent will display this (or at least some of it) in the job step history.
                # Need to use Set-Variable or changes to the variable will only be in scope within the function and we want to persist this.
                if ($errors -eq 0) {
                    Set-Variable -Name errors -Scope 1 -Value 1
                }
            }
        }
    }
}

# Output the scripts
CopyObjectsToDestination $assemblies
CopyObjectsToDestination $tbl 
CopyObjectsToDestination $udfs
CopyObjectsToDestination $views 
CopyObjectsToDestination $storedProcs 
CopyObjectsToDestination $catalogs
CopyObjectsToDestination $udtts 

# Disconnect from databases cleanly.
$sourceSrv.ConnectionContext.Disconnect()
$destSrv.ConnectionContext.Disconnect()

# Did we encounter any non-fatal errors along the way (SQL errors and suchlike)? If yes then throw an exception which tells the
# user to check the log files.
if ($errors -eq 1) { 
    throw "Errors encountered - see log file for details"
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM