8

Say I have a local database named MyDatabase. I want to move it to Azure SQL and replace an existing database currently residing there named MyDatabase. I know how to create a BACPAC file locally. I know how to import the BACPAC to my Azure storage account. However, once the BACPAC is in Azure storage, I don't know the preferred way of overwriting the existing MyDatabase database with the copy in storage. I could import the BACPAC file and create a second database, then delete the first, and rename the database just imported. However, is the best or preferred way of doing this?

2 Answers 2

14

You are correct. In Azure you cannot restore on an existing database, only "a new or empty one".

  • You have to restore with a different name.
  • Delete old database
  • Rename new one to old database name.

You have few ways to restore from .BACPAC file.

  1. You can do it directly from your on prem .BACPAC location by using .\sqlpackage.exe command line tool.

    .\sqlpackage.exe /a:Import /sf:C:\filename.bacpac /tsn:ServerName.database.windows.net /tdn:destinationDBName ` /tu:adminaccountName@serverName /tp:$credentialPW

  2. You can also use the copy that you uploaded in your storage account.

    $ResourceGroupName = "RGName" $ServerName = 'ServerName' $DatabaseName = "DestinationDBName"

    $StorageName = "StorageAccountName" $StorageKeyType = "StorageAccessKey" $StorageUri = "http://$StorageName.blob.core.windows.net/swwstoragecontainer/BackpacFileName.bacpac" $StorageKey = "***********************************"

    $credential = Get-Credential

    $importRequest = New-AzureRmSqlDatabaseImport -ResourceGroupName $ResourceGroupName -ServerName $ServerName -DatabaseName $DatabaseName -StorageKeytype $StorageKeyType -StorageKey $StorageKey -StorageUri $StorageUri -AdministratorLogin $credential.UserName -AdministratorLoginPassword $credential.Password ` -Edition Standard -ServiceObjectiveName S0 -DatabaseMaxSizeBytes 50000

    Get-AzureRmSqlDatabaseImportExportStatus -OperationStatusLink $importRequest.OperationStatusLink

  3. In portal you can directly import the .BACPAC file into your server as a database.

5
  • 3
    It appears I can also use SSMS to deploy my local copy to Azure SQL by right-clicking on the database in SSMS, choosing Tasks and then Deploy Database to Microsoft SQL Azure. Have you done this? May 27, 2017 at 20:21
  • 2
    You are correct, yes I did. This is one of the easiest way I show in my presentation. Details here. May 27, 2017 at 22:47
  • I've tried this script and the one using the newer Az PS modules - but both just give me a 500 error with no further explanation :( Jan 6, 2021 at 16:24
  • @IanGrainger with new Az module commands name is different. For example New-AzureRmSqlDatabaseImport does not exist in the new module, you need to use New-AzSqlDatabaseImport. Jan 18, 2021 at 20:45
  • 1
    @RandyMinder WOW! Just saw this capability! That's awesome, had no idea!!!!! WIsh this was an answer someplace so I could give you some points too!
    – ganders
    May 4, 2021 at 5:17
8

In Azure you cannot restore on an existing database. (c)

Apparently, not really. You CAN restore a .bacpac file into existing Azure SQL database, for example, in a case when you really need to keep the same instance of Azure SQL database, as it's incorporated in Azure environment. A necessary condition for that is: the target DB must be empty, i.e. like just created as new. But if you already have a target DB, which is not empty (of course!), you can "clean" the database, running the following script in its context, being logged in as a superuser:

DECLARE @sql NVARCHAR(2000)

WHILE EXISTS(SELECT TOP(1) * FROM SYS.TRIGGERS WHERE is_ms_shipped = 0)
BEGIN
    SELECT TOP(1) @sql = 'DROP TRIGGER IF EXISTS [' + [name] + '] ON ' + parent_class_desc COLLATE database_default --SQL_Latin1_General_CP1_CI_AS
    FROM SYS.TRIGGERS
    WHERE is_ms_shipped = 0
    PRINT @sql
    EXEC (@sql)
END

WHILE EXISTS(SELECT TOP(1) * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE')
BEGIN
    SELECT TOP(1) @sql = 'DROP PROCEDURE IF EXISTS [' + ROUTINE_SCHEMA + '].[' + ROUTINE_NAME + ']'
    FROM INFORMATION_SCHEMA.ROUTINES
    WHERE ROUTINE_TYPE = 'PROCEDURE'
    PRINT @sql
    EXEC (@sql)
END

WHILE EXISTS(SELECT TOP(1) * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION')
BEGIN
    SELECT TOP(1) @sql = 'DROP FUNCTION IF EXISTS [' + ROUTINE_SCHEMA + '].[' + ROUTINE_NAME + ']'
    FROM INFORMATION_SCHEMA.ROUTINES
    WHERE ROUTINE_TYPE = 'FUNCTION'
    PRINT @sql
    EXEC (@sql)
END

WHILE EXISTS(SELECT TOP(1) * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='FOREIGN KEY')
BEGIN
    SELECT TOP(1) @sql = 'ALTER TABLE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']'
    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
    WHERE CONSTRAINT_TYPE='FOREIGN KEY'
    PRINT @sql
    EXEC (@sql)
END

WHILE EXISTS(SELECT TOP(1) * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA != 'sys')
BEGIN
    SELECT TOP(1) @sql = 'DROP VIEW [' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']'
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA != 'sys'
    PRINT @sql
    EXEC (@sql)
END

WHILE EXISTS(SELECT TOP(1) * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME != '__MigrationHistory')
BEGIN
    SELECT TOP(1) @sql = 'DROP TABLE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']'
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME != '__MigrationHistory'
    PRINT @sql
    EXEC (@sql)
END

--SELECT * FROM SYS.TYPES WHERE is_user_defined = 1
--SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME != '__MigrationHistory'
--SELECT * FROM SYS.TRIGGERS WHERE is_ms_shipped = 0
--DROP TRIGGER IF EXISTS [backup_objects] ON DATABASE

Last 4 statements are optional. First 3 of them are for checking/viewing of some parameters, and last one is used for dropping a specific database-level trigger if it exists.

After that, you can restore the .bacpac file you have, to the target DB using the standard sqlpackage.exe utility, running it in the Administrative-elevated command line window, like this:

“C:\Program Files (x86)\Microsoft SQL Server\140\DAC\bin\sqlpackage.exe” /a:Import /sf:"C:\Users\[username1]\Documents\SQL Server Management Studio\DAC Packages\[SourceDBName.bacpac]" /tsn:[azureSQLServerName].database.windows.net /tdn:[TargetAzureSQLDBName] /tu:[DBAdminLogin] /tp:[DBAdminPassword]

Just replace [braced_values] with real ones, and it should work. Upon running, the utility may show a warning message, displayed with yellow color, like this:

Initializing deployment The object [data_0] exists in the target, but it will not be dropped even though you selected the 'Generate drop statements for objects that are in the target database but that are not in the source' check box. The object [log] exists in the target, but it will not be dropped even though you selected the 'Generate drop statements for objects that are in the target database but that are not in the source' check box.

You can just disregard it. Depending of the database size and complexity, the restoring process may take a long time, so make sure to wait until it finishes, displaying the message: Successfully imported database.

Hope that helps.

1
  • When you have custom schema's, you can also drop these with same kind of sql for SYS.schemas + where name not in ('dbo', 'guest','INFORMATION_SCHEMA', 'sys', 'db_owner', 'db_accessadmin','db_securityadmin','db_ddladmin','db_backupoperator','db_datareader','db_datawriter','db_denydatareader','db_denydatawrite')
    – Hans Derks
    Apr 24, 2020 at 13:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.