【问题标题】:How can I clone an SQL Server database on the same server in SQL Server 2008 Express?如何在 SQL Server 2008 Express 的同一台服务器上克隆 SQL Server 数据库?
【发布时间】:2011-04-19 06:14:50
【问题描述】:

我有一个 MS SQL Server 2008 Express 系统,其中包含一个我想“复制和重命名”(用于测试目的)的数据库,但我不知道实现此目的的简单方法。

我注意到在 R2 版本的 SQL Server 中有一个复制数据库向导,但遗憾的是我无法升级。

有问题的数据库围绕着一个演出。 我尝试将要复制的数据库的备份还原到新数据库中,但没有成功。

【问题讨论】:

  • 恢复备份应该可以。您能否提供有关失败原因的更多详细信息?
  • 我意识到我在从备份恢复时犯了一个错误。我首先创建了一个新的空数据库并尝试从那里恢复备份。我应该做的是打开恢复对话框并在其中键入新数据库的名称,而不是先创建它。这样做很好地克隆了数据库!
  • 当我尝试以不同的名称恢复数据库时,它只是给了我:“恢复数据库'我的数据库(新)'失败。...无法获得独占访问权限,因为数据库是正在使用。” - 新名称下的数据库不存在,怎么可能使用?!

标签: sql-server sql-server-2008-express


【解决方案1】:

<head>
    <title>Copy Database</title>
</head>

<body>
    
    <?php
    
    $servername = "localhost:xxxx";
    $user1 = "user1";
    $pw1 = "pw1";
    $db1 = "db1";
    
    $conn1 = new mysqli($servername,$user1,$pw1,$db1);
    
    if($conn1->connect_error) {
        die("Conn1 failed: " . $conn1->connect_error);
    }
    
    $user2 = "user2";
    $pw2 = "pw2";
    $db2 = "db2";
    
    $conn2 = new mysqli($servername,$user2,$pw2,$db2);
    
    if($conn2->connect_error) {
        die("Conn2 failed: " . $conn2->connect_error);
    }
    
    $sqlDB1 = "SELECT * FROM table1";
    $resultDB1 = $conn1->query($sqlDB1);
    
    if($resultDB1->num_rows > 0) {
        while($row = $resultDB1->fetch_assoc()) {
            $sqlDB2 = "INSERT INTO table2 (col1, col2) VALUES ('" . $row["tableRow1"] . "','" . $row["tableRow2"] . "')";
            $resultDB2 = $conn2->query($sqlDB2);
        }
    }else{
        echo "0 results";
    }
    
    $conn1->close();
    $conn2->close();
    
    ?>
    
</body>

【讨论】:

【解决方案2】:

来自 SSMS:

1 - 将原始数据库备份到 .BAK 文件(your_source_db -> 任务 -> 备份)。

2 - 右键单击​​“数据库”和“恢复数据库”

3 - 设备 > ...(按钮)> 添加 > 选择 your_source_db.bak

4 - 在“常规”选项卡的“目标”部分,将“数据库”中的 your_source_db 重命名为 new_name_db

5 - 在“文件”选项卡中,勾选“将所有文件重新定位到文件夹”,

  • 在“Restore As”列中重命​​名两个线以保持与 new_name_db (.mdf, _log.ldf) 的一致性

6 - 在“选项”选项卡的“恢复选项”部分,勾选两个第一个选项(“覆盖...”、“保留...”)和“恢复状态”:“恢复时恢复”

  • 还要确保取消选中“尾日志备份”部分中的选项以避免将源数据库保持在“恢复状态”!

【讨论】:

    【解决方案3】:

    这是我使用的脚本。有点棘手,但它有效。在 SQL Server 2012 上测试。

    DECLARE @backupPath nvarchar(400);
    DECLARE @sourceDb nvarchar(50);
    DECLARE @sourceDb_log nvarchar(50);
    DECLARE @destDb nvarchar(50);
    DECLARE @destMdf nvarchar(100);
    DECLARE @destLdf nvarchar(100);
    DECLARE @sqlServerDbFolder nvarchar(100);
    
    SET @sourceDb = 'db1'
    SET @sourceDb_log = @sourceDb + '_log'
    SET @backupPath = 'E:\DB SQL\MSSQL11.MSSQLSERVER\MSSQL\Backup\' + @sourceDb + '.bak'    --ATTENTION: file must already exist and SQL Server must have access to it
    SET @sqlServerDbFolder = 'E:\DB SQL\MSSQL11.MSSQLSERVER\MSSQL\DATA\'
    SET @destDb = 'db2'
    SET @destMdf = @sqlServerDbFolder + @destDb + '.mdf'
    SET @destLdf = @sqlServerDbFolder + @destDb + '_log' + '.ldf'
    
    BACKUP DATABASE @sourceDb TO DISK = @backupPath
    
    RESTORE DATABASE @destDb FROM DISK = @backupPath
    WITH REPLACE,
       MOVE @sourceDb     TO @destMdf,
       MOVE @sourceDb_log TO @destLdf
    

    【讨论】:

    • 在我的环境中,文件名与数据库名称不匹配(来自 another 恢复)所以我需要 SET @sourceDb_log = (SELECT files.name FROM sys.databases dbs INNER JOIN sys.master_files files ON dbs.database_id=files.database_id WHERE dbs.name=@sourceDb AND files.type=1) 和 @sourceDb_data 的单独变量类似的查询(替换为files.type=0)。 HTH!
    • 得到一个错误:Msg 137, Level 15, State 2, Line 25 Must declare the scalar variable "@destDb". 原来我在变量声明和它的使用之间放了一个GO 声明,我们不能这样做,请参阅:stackoverflow.com/a/55347161/6184866
    • 确实非常使用(r)完整脚本... ;) 一个小的语法更正:只需在第 11 行的变量上放置一个 '@'SET @backupPath = 'E:\tmp\' + @sourceDb + '.bak' --ATTENTION: file must already exist and SQL Server must have access to it. 此外,您可以将备份文件夹设置为: ` E:\DB SQL\MSSQL11.MSSQLSERVER\MSSQL\Backup\ ` 避免设置安全访问权限。
    【解决方案4】:
    1. 安装 Microsoft SQL Management Studio,您可以从 Microsoft 网站免费下载:

      2008 版

      Microsoft SQL Management Studio 2008 是 SQL Server 2008 Express with Advanced Services 的一部分

      2012 版

      点击download button查看ENU\x64\SQLManagementStudio_x64_ENU.exe

      2014 版

      点击download button查看MgmtStudio 64BIT\SQLManagementStudio_x64_ENU.exe

    2. 打开 Microsoft SQL Management Studio

    3. 将原始数据库备份到 .BAK 文件(db -> 任务 -> 备份)。
    4. 使用新名称创建空数据库(克隆)。请注意下面的 cmets,因为这是可选的。
    5. 单击以克隆数据库并打开恢复对话框(见图)
    6. 选择设备并添加步骤 3 中的备份文件。
    7. 将目标更改为测试数据库
    8. 更改数据库文件的位置,它必须与原始位置不同。您可以直接在文本框中输入,只需添加后缀。 (注意:顺序很重要。选择复选框,然后更改文件名。)
    9. 检查 WITH REPLACE 和 WITH KEEP_REPLICATION

    【讨论】:

    • 1.不要创建空数据库并将 .bak 文件还原到其中。 2. 使用可通过右键单击 SQL Server Management Studio 的“数据库”分支访问的“恢复数据库”选项,并在提供要恢复的源的同时提供数据库名称。参考:stackoverflow.com/questions/10204480/…
    • Microsoft SQL Management Studio - 免费
    • 不起作用 - “无法获得独占访问权限,因为数据库正在使用中”。
    • 我还必须取消选中“还原前进行尾日志备份”。默认情况下已检查,并导致“无法获得独占访问权限,因为数据库正在使用中”错误。
    • 我的原始数据库卡在“正在恢复”中
    【解决方案5】:

    另一种方法是使用导入/导出向导,首先创建一个空数据库,然后选择源数据库作为您的服务器的源,然后在目标中选择相同的服务器与目标数据库(使用您首先创建的空数据库),然后点击完成

    它将创建所有表并将所有数据传输到新数据库中,

    【讨论】:

    • 感谢月亮和回来!
    【解决方案6】:

    您可以只创建一个新数据库,然后转到任务,导入数据,然后将要复制的数据库中的所有数据导入刚刚创建的数据库。

    【讨论】:

      【解决方案7】:

      基于 Joe 回答的脚本(分离、复制文件、附加两者)。

      1. 以管理员帐户运行 Managment Studio。

      这不是必需的,但执行时可能会出现访问被拒绝错误。

      1. 配置 sql server 以执行 xp_cmdshel
      EXEC sp_configure 'show advanced options', 1
      GO
      RECONFIGURE
      GO
      EXEC sp_configure 'xp_cmdshell', 1
      GO
      RECONFIGURE
      GO
      
      1. 运行脚本,但之前在@dbName@copyDBName 变量中输入您的数据库名称。
      USE master;
      GO 
      
      DECLARE @dbName NVARCHAR(255) = 'Products'
      DECLARE @copyDBName NVARCHAR(255) = 'Products_branch'
      
      -- get DB files
      CREATE TABLE ##DBFileNames([FileName] NVARCHAR(255))
      EXEC('
          INSERT INTO ##DBFileNames([FileName])
          SELECT [filename] FROM ' + @dbName + '.sys.sysfiles')
      
      -- drop connections
      EXEC('ALTER DATABASE ' + @dbName + ' SET OFFLINE WITH ROLLBACK IMMEDIATE')
      
      EXEC('ALTER DATABASE ' + @dbName + ' SET SINGLE_USER')
      
      -- detach
      EXEC('EXEC sp_detach_db @dbname = ''' + @dbName + '''')
      
      -- copy files
      DECLARE @filename NVARCHAR(255), @path NVARCHAR(255), @ext NVARCHAR(255), @copyFileName NVARCHAR(255), @command NVARCHAR(MAX) = ''
      DECLARE 
          @oldAttachCommand NVARCHAR(MAX) = 
              'CREATE DATABASE ' + @dbName + ' ON ', 
          @newAttachCommand NVARCHAR(MAX) = 
              'CREATE DATABASE ' + @copyDBName + ' ON '
      
      DECLARE curs CURSOR FOR 
      SELECT [filename] FROM ##DBFileNames
      OPEN curs  
      FETCH NEXT FROM curs INTO @filename
      WHILE @@FETCH_STATUS = 0  
      BEGIN
          SET @path = REVERSE(RIGHT(REVERSE(@filename),(LEN(@filename)-CHARINDEX('\', REVERSE(@filename),1))+1))
          SET @ext = RIGHT(@filename,4)
          SET @copyFileName = @path + @copyDBName + @ext
      
          SET @command = 'EXEC master..xp_cmdshell ''COPY "' + @filename + '" "' + @copyFileName + '"'''
          PRINT @command
          EXEC(@command);
      
          SET @oldAttachCommand = @oldAttachCommand + '(FILENAME = "' + @filename + '"),'
          SET @newAttachCommand = @newAttachCommand + '(FILENAME = "' + @copyFileName + '"),'
      
          FETCH NEXT FROM curs INTO @filename
      END
      CLOSE curs 
      DEALLOCATE curs
      
      -- attach
      SET @oldAttachCommand = LEFT(@oldAttachCommand, LEN(@oldAttachCommand) - 1) + ' FOR ATTACH'
      SET @newAttachCommand = LEFT(@newAttachCommand, LEN(@newAttachCommand) - 1) + ' FOR ATTACH'
      
      -- attach old db
      PRINT @oldAttachCommand
      EXEC(@oldAttachCommand)
      
      -- attach copy db
      PRINT @newAttachCommand
      EXEC(@newAttachCommand)
      
      DROP TABLE ##DBFileNames
      

      【讨论】:

        【解决方案8】:

        解决方案,基于此评论:https://stackoverflow.com/a/22409447/2399045。 只需设置设置:数据库名称、临时文件夹、数据库文件文件夹。 运行后,您将获得名称为“sourceDBName_yyyy-mm-dd”格式的数据库副本。

        -- Settings --
        -- New DB name will have name = sourceDB_yyyy-mm-dd
        declare @sourceDbName nvarchar(50) = 'MyDbName';
        declare @tmpFolder nvarchar(50) = 'C:\Temp\'
        declare @sqlServerDbFolder nvarchar(100) = 'C:\Databases\'
        
        --  Execution --
        declare @sourceDbFile nvarchar(50);
        declare @sourceDbFileLog nvarchar(50);
        declare @destinationDbName nvarchar(50) = @sourceDbName + '_' + (select convert(varchar(10),getdate(), 121))
        declare @backupPath nvarchar(400) = @tmpFolder + @destinationDbName + '.bak'
        declare @destMdf nvarchar(100) = @sqlServerDbFolder + @destinationDbName + '.mdf'
        declare @destLdf nvarchar(100) = @sqlServerDbFolder + @destinationDbName + '_log' + '.ldf'
        
        SET @sourceDbFile = (SELECT top 1 files.name 
                            FROM sys.databases dbs 
                            INNER JOIN sys.master_files files 
                                ON dbs.database_id = files.database_id 
                            WHERE dbs.name = @sourceDbName
                                AND files.[type] = 0)
        
        SET @sourceDbFileLog = (SELECT top 1 files.name 
                            FROM sys.databases dbs 
                            INNER JOIN sys.master_files files 
                                ON dbs.database_id = files.database_id 
                            WHERE dbs.name = @sourceDbName
                                AND files.[type] = 1)
        
        BACKUP DATABASE @sourceDbName TO DISK = @backupPath
        
        RESTORE DATABASE @destinationDbName FROM DISK = @backupPath
        WITH REPLACE,
           MOVE @sourceDbFile     TO @destMdf,
           MOVE @sourceDbFileLog  TO @destLdf
        

        【讨论】:

        • 帕维尔,谢谢你的回答。如果您不介意,我会添加动态 SQL,以便它可以重命名逻辑文件名:DECLARE @DynamicSQL [nvarchar](2000);SET @DynamicSQL = CONCAT('ALTER DATABASE [', @DestinationDBName, '] MODIFY FILE (NAME = ''', @SourceDBName, ''', NEWNAME = ''', @DestinationDBName, ''');');SET @DynamicSQL = CONCAT(@DynamicSQL, 'ALTER DATABASE [', @DestinationDBName, '] MODIFY FILE (NAME = ''', CONCAT(@SourceDBName, '_log'), ''', NEWNAME = ''', CONCAT(@DestinationDBName, '_log'), ''');');EXECUTE (@DynamicSQL);
        【解决方案9】:

        这里提到的解决方案都不适合我 - 我使用的是 SQL Server Management Studio 2014。

        相反,我不得不取消选中“选项”屏幕中的“恢复前进行尾日志备份”复选框:在我的版本中,默认情况下它被选中,并阻止完成恢复操作。 取消选中后,还原操作继续进行,没有问题。

        【讨论】:

        • 这个答案拯救了我的一天。
        • 也拯救了我的一天 :)
        • 当不使用 SQL Server 2017 执行此操作时,原始数据库仍处于“正在恢复...”中。您的解决方案成功了 - 谢谢!
        【解决方案10】:

        右键单击要克隆的数据库,单击Tasks,单击Copy Database...。按照向导操作即可。

        【讨论】:

        • 我认为这只能在 SQL Server 的 R2 版本中使用 :-(
        • 这是它在 express 中的工作方式:stackoverflow.com/questions/4269450/…
        • 如果您的数据库中有加密对象,这将不起作用。
        • 我想说,重点其实是在哪里做呢?你描述的很直观。我之前已经在某些工具(0xDBE、Visual Studio SQL Server 对象资源管理器)中尝试过,但在那里没有找到这样的功能。
        • 不可能!任务 -> 没有复制数据库的菜单项
        【解决方案11】:

        使用 MS SQL Server 2012,您需要执行 3 个基本步骤:

        1. 首先,生成.sql文件,只包含源DB的结构

          • 右键单击源数据库,然后 Tasks 然后 Generate Scripts
          • 按照向导并在本地保存 .sql 文件
        2. 其次,将源数据库替换为.sql文件中的目标数据库

          • 右键单击目标文件,选择New QueryCtrl-H或(编辑 - 查找和替换 em> - 快速替换)
        3. 最后,填充数据

          • 右键单击目标数据库,然后选择 TasksImport Data
          • 数据源下拉设置为“.net framework data provider for SQL server”+设置DATA下的连接字符串文本字段例如:Data Source=Mehdi\SQLEXPRESS;Initial Catalog=db_test;User ID=sa;Password=sqlrpwrd15
          • 对目的地做同样的事情
          • 选中您要传输的表或选中“源:...”旁边的复选框以检查所有表

        你已经完成了。

        【讨论】:

        • 顺便说一句,如果目标表中不存在导入数据,我猜可以创建表.. 简单的解决方案 +1
        【解决方案12】:

        您可以尝试分离数据库,在命令提示符下将文件复制到新名称,然后附加两个数据库。

        在 SQL 中:

        USE master;
        GO 
        EXEC sp_detach_db
            @dbname = N'OriginalDB';
        GO
        

        在命令提示符下(为了这个示例,我已经简化了文件路径):

        copy c:\OriginalDB.mdf c:\NewDB.mdf
        copy c:\OriginalDB.ldf c:\NewDB.ldf
        

        再次在 SQL 中:

        USE master;
        GO
        CREATE DATABASE OriginalDB
            ON (FILENAME = 'C:\OriginalDB.mdf'),
               (FILENAME = 'C:\OriginalDB.ldf')
            FOR ATTACH;
        GO
        CREATE DATABASE NewDB
            ON (FILENAME = 'C:\NewDB.mdf'),
               (FILENAME = 'C:\NewDB.ldf')
            FOR ATTACH;
        GO
        

        【讨论】:

        • 完美!这是对我有用的独特解决方案!非常感谢!
        • select * from OriginalDB.sys.sysfiles 查找数据库文件的位置。
        • 是的,我也最喜欢这个解决方案,因为它不需要任何特殊工具。但我无法创建 NewDB,它在 .mdf 文件上显示 Permission denied。我现在不需要它,我只需要原始数据库的备份,这样我以后可以用它覆盖原始数据库,我只是好奇为什么会出现这样的错误。
        • 如果可以停止sql服务,复制mdf和ldf文件,为新数据库重命名,再次启动sql服务并运行最后一个,则不必分离原始数据库master下创建数据库命令:USE master;去创建数据库 NewDB ON (FILENAME = 'C:\NewDB.mdf'), (FILENAME = 'C:\NewDB.ldf') FOR ATTACH;去
        • +1 是最快的方式。除了@JohnLBevan 优秀评论,还可以使用exec sp_helpdb @dbname='TEMPDB';
        【解决方案13】:

        在 SQL Server 2008 R2 中,将数据库作为文件备份到文件夹中。 然后选择出现在“数据库”文件夹中的恢复选项。 在向导中,输入您希望在目标数据库中使用的新名称。 并选择从文件中恢复并使用您刚刚创建的文件。 我只是做到了,而且速度非常快(我的数据库很小,但仍然) 巴勃罗。

        【讨论】:

          【解决方案14】:

          事实证明,我曾错误地尝试从备份中恢复。

          最初我创建了一个新数据库,然后尝试在此处恢复备份。 我应该做的,并且最终起作用的是,打开恢复对话框并在目标字段中输入新数据库的名称。

          所以,简而言之,从备份中恢复就可以了。

          感谢大家的反馈和建议

          【讨论】:

          • 当我这样做时,对话框告诉我文件与我最初备份的数据库位于同一位置。所以没勇气恢复,怕文件被覆盖。
          • Neils,默认情况下,您拍摄的快照中的文件是相同的。您可以更改它们的名称以为新命名的数据库创建新文件。
          • PS:此方法需要SQL Agent服务,在开始db复制操作前请确保它正在运行。
          • 你现在已经用这个答案帮助了我三遍。我一直忘记输入它而不是创建它。 +啤酒
          • 这和重命名“文件”窗口中的 .mdf 和 .log 文件对我有用。
          【解决方案15】:

          如果数据库不是很大,您可以查看 SQL Server Management Studio Express 中的“脚本数据库”命令,这些命令位于资源管理器中数据库项本身的上下文菜单中。

          您可以选择要编写的所有内容;当然,您需要对象和数据。然后,您会将整个脚本保存到一个文件中。然后您可以使用该文件重新创建数据库;只需确保顶部的 USE 命令设置为正确的数据库即可。

          【讨论】:

          • 谢谢,但是数据库非常大,(大约一个演出)所以我认为可能会发生不好的事情:-)
          • 对;那不是最好的方法。相反,您可以使用脚本数据库在新数据库中创建结构,然后导入/导出来移动数据。只要确保你先做脚本数据库;如果表不存在,Import/Export 将创建表,您可能不喜欢它的方式。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-26
          • 1970-01-01
          • 2010-09-22
          • 2011-05-06
          • 1970-01-01
          相关资源
          最近更新 更多