复制一个 SQL Server 2008 数据库并将其重命名

12

我有一个SQL Server 2008数据库,想要复制并在服务器上创建一个新的数据库(使用不同的名称)。我不关心保留数据,新数据库可以首先创建没有数据。我要做的是以下几点:

  • 创建新数据库并保持旧数据库的结构
  • 设置新数据库名称
  • 将所有varchar和char数据类型更改为nvarchar和nchar
  • 将所有文本数据类型更改为nvarchar(MAX)

另外,我有两个问题不是我的任务的一部分,但是希望考虑以下:

  • 如何升级SQL Server数据库到SQL Server 2012?
  • 是否需要进行任何准备工作来确保我能够轻松升级它?
2个回答

31
这实际上是多个问题的组合。

问题1和2

  • 创建新数据库,保留旧数据库结构
  • 设置新数据库名称

最简单的备份命令是:

BACKUP DATABASE dbname TO DISK = 'C:\some folder\dbname.bak' WITH INIT;
-- or WITH INIT, COMPRESSION if you are on Enterprise or Developer

现在如果要将其作为不同的数据库进行恢复,您需要知道文件名,因为它会尝试将相同的文件放在相同的位置。因此,如果您运行以下命令:
EXEC dbname.dbo.sp_helpfile;

您应该看到输出结果包含数据和日志文件的名称和路径。在构建恢复过程时,需要使用这些路径,但将路径替换为新数据库的名称,例如:
RESTORE DATABASE newname FROM DISK = 'C:\some folder\dbname.bak'
  WITH MOVE 'dbname' TO 'C:\path_from_sp_helpfile_output\newname_data.mdf',
  MOVE 'dbname_log' TO 'C:\path_from_sp_helpfile_output\newname_log.ldf';

你需要用你实际的数据库名称替换dbnamenewname,也需要用你实际的路径替换C:\ some folderC:\ path_from_sp_helpfile_output \ 。除非我知道那些是什么,否则我无法在我的答案中提供更具体的信息。

这里是完整的复现:

CREATE DATABASE [DB-A];
GO

EXEC [DB-A].dbo.sp_helpfile;

部分结果:
name     fileid filename
-------- ------ ---------------------------------
DB-A     1      C:\Program Files\...\DB-A.mdf
DB-A_log 2      C:\Program Files\...\DB-A_log.ldf

现在我运行备份:
BACKUP DATABASE [DB-A] TO DISK = 'C:\dev\DB-A.bak' WITH INIT;

当然,如果克隆目标(在这种情况下是DB-B)已经存在,您将需要删除它:
USE [master];
GO
IF DB_ID('DB-B') IS NOT NULL
BEGIN
  ALTER DATABASE [DB-B] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
  DROP DATABASE [DB-B];
END
GO

现在这个还原将会成功运行,它将会给你一个以DB-B为名的DB-A的副本。
RESTORE DATABASE [DB-B] FROM DISK = 'C:\dev\DB-A.bak'
  WITH MOVE 'DB-A'     TO 'C:\Program Files\...\DB-B.mdf',
       MOVE 'DB-A_log' TO 'C:\Program Files\...\DB-B_log.ldf';

问题3和4

  • 将所有varchar和char数据类型更改为nvarchar和nchar
  • 将所有文本数据类型更改为nvarchar(MAX)

重构是一个很大的痛点,特别是当一些列参与约束时。你可以用这种方式构建一个非常基本的脚本,但你需要更强大的工具来处理所有这些变量。这假设所有的列都可为空,并且不参与约束。
DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += '
  ALTER TABLE ' + 
  QUOTENAME(OBJECT_SCHEMA_NAME(c.[object_id])) 
  + '.' + QUOTENAME(OBJECT_NAME(c.[object_id]))
  + ' ALTER COLUMN ' + QUOTENAME(c.name) + ' '
  + CASE t.name WHEN N'text' 
     THEN N'nvarchar(max)' 
     ELSE N'n' + t.name + '(' + RTRIM(c.max_length) + ')'
  END + ';'
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON c.user_type_id = t.user_type_id
WHERE c.system_type_id IN (35, 167, 175)
AND OBJECTPROPERTY(c.[object_id], 'IsMsShipped') = 0;

PRINT @sql;
-- EXEC sp_executesql @sql;

你可以使用PRINT输出来验证脚本的前8K部分,当你认为看起来不错时,取消注释EXEC

完成后,您需要重建所有索引。

话虽如此,像Tony建议的那样编写数据库脚本(或使用Red Gate的SQL Compare之类的工具 - 或者其许多替代品 - 对比空数据库)可能会更容易,特别是如果其中一些列参与约束 - 这些约束可能需要被删除并重新创建以改变类型。


问题5和6

  • 如何将SQL Server数据库升级到SQL Server 2012?
  • 是否需要进行任何准备工作,以确保我可以轻松升级它?

您不能仅升级2008实例上的单个数据库。您可以进行就地升级或设置新实例(如Tony所述),然后迁移您的数据库(最好使用备份/还原 - 许多人会告诉您要分离/附加,但这不太安全)。您应该做的准备工作包括:

升级后,您需要:

  • 将兼容性级别设置为110。
  • 更新所有统计信息。

1
一句话,美妙极了!谢谢。 - Mike Malter

2

复制数据库脚本的来源。

点击此处查看脚本。

USE master;

DECLARE
    @SourceDatabaseName AS SYSNAME = '<SourceDB>', 
    @TargetDatabaseName AS SYSNAME = '<TargetDB>'



-- ============================================
-- Define path where backup will be saved
-- ============================================
IF NOT EXISTS (SELECT 1 FROM sys.databases WHERE name = @SourceDatabaseName)
    RAISERROR ('Variable @SourceDatabaseName is not set correctly !', 20, 1) WITH LOG       

DECLARE @SourceBackupFilePath varchar(2000)
SELECT @SourceBackupFilePath = BMF.physical_device_name
FROM
    msdb.dbo.backupset B
    JOIN msdb.dbo.backupmediafamily BMF ON B.media_set_id = BMF.media_set_id
WHERE B.database_name = @SourceDatabaseName
ORDER BY B.backup_finish_date DESC

SET @SourceBackupFilePath = REPLACE(@SourceBackupFilePath, '.bak', '_clone.bak')

IF @SourceBackupFilePath IS NULL
        RAISERROR ('Could not determine file path for backup file!', 16, 1) WITH LOG



-- ============================================
-- Backup source database
-- ============================================
DECLARE @Sql NVARCHAR(MAX) 
SET @Sql = 'BACKUP DATABASE @SourceDatabaseName TO DISK = ''@SourceBackupFilePath'''
SET @Sql = REPLACE(@Sql, '@SourceDatabaseName', @SourceDatabaseName)
SET @Sql = REPLACE(@Sql, '@SourceBackupFilePath', @SourceBackupFilePath)
SELECT 'Performing backup...', @Sql as ExecutedSql
EXEC (@Sql)



-- ============================================
-- Automatically compose database files (.mdf and .ldf) paths
-- ============================================
DECLARE
          @LogicalDataFileName as NVARCHAR(MAX)
        , @LogicalLogFileName as NVARCHAR(MAX)
        , @TargetDataFilePath as NVARCHAR(MAX)
        , @TargetLogFilePath as NVARCHAR(MAX)

SELECT
        @LogicalDataFileName = name,
        @TargetDataFilePath = SUBSTRING(physical_name,1,LEN(physical_name)-CHARINDEX('\',REVERSE(physical_name))) + '\' + @TargetDatabaseName + '.mdf'
FROM sys.master_files
WHERE
        database_id = DB_ID(@SourceDatabaseName)        
        AND type = 0            -- datafile file

SELECT
        @LogicalLogFileName = name,
        @TargetLogFilePath = SUBSTRING(physical_name,1,LEN(physical_name)-CHARINDEX('\',REVERSE(physical_name))) + '\' + @TargetDatabaseName + '.ldf'
FROM sys.master_files
WHERE
        database_id = DB_ID(@SourceDatabaseName)        
        AND type = 1            -- log file     

SELECT  
    @LogicalDataFileName as LogicalDataFileName,
    @LogicalLogFileName as LogicalLogFileName,
    @TargetDataFilePath as TargetDataFilePath,
    @TargetLogFilePath as TargetLogFilePath                

IF @TargetDataFilePath IS NULL OR @TargetLogFilePath IS NULL
    RAISERROR ('Could not determine target paths!', 16, 1) WITH LOG



-- ============================================
-- Restore target database
-- ============================================
IF EXISTS (SELECT 1 FROM sys.databases WHERE name = @TargetDatabaseName)
    RAISERROR ('A database with the same name already exists!', 20, 1) WITH LOG        

SET @Sql = 'RESTORE DATABASE @TargetDatabaseName
FROM DISK = ''@SourceBackupFilePath'' 
WITH MOVE ''@LogicalDataFileName'' TO ''@TargetDataFilePath'',
MOVE ''@LogicalLogFileName'' TO ''@TargetLogFilePath''' 
SET @Sql = REPLACE(@Sql, '@TargetDatabaseName', @TargetDatabaseName)
SET @Sql = REPLACE(@Sql, '@SourceBackupFilePath', @SourceBackupFilePath)
SET @Sql = REPLACE(@Sql, '@LogicalDataFileName', @LogicalDataFileName)
SET @Sql = REPLACE(@Sql, '@TargetDataFilePath', @TargetDataFilePath)
SET @Sql = REPLACE(@Sql, '@LogicalLogFileName', @LogicalLogFileName)
SET @Sql = REPLACE(@Sql, '@TargetLogFilePath', @TargetLogFilePath)
SELECT 'Restoring...', @Sql as ExecutedSql
EXEC (@Sql)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接