【问题标题】:How can I programatically clone a database schema in SQL Server?如何以编程方式克隆 SQL Server 中的数据库架构?
【发布时间】:2010-10-07 01:09:32
【问题描述】:

我想对我的项目进行一些可靠的测试,我想这样做的方式是有一个我可以运行的命令行程序,它只会复制数据库的结构而不是实际数据。然后我可以在那个新数据库上运行我的测试。

想法?

更新:有人说我应该指定一种语言。如果 Sql Server 运行,我认为 TSQL 就是这样,脚本应该运行。另外,它是 SQL Server 2005。

【问题讨论】:

  • 您可能应该指定一种语言以获得更好的答案

标签: sql-server


【解决方案1】:

您可以通过编程方式完成您的要求。这些是步骤:

  1. 测试您的“source_test”数据库是否存在,如果存在,请将其删除。
  2. 连接到您的源数据库,
  3. 创建源数据库的备份
  4. 在重命名实际数据库文件时将源数据库恢复到“source_test”数据库
  5. 执行 SQL Server 实用程序存储过程,exec sp_msforeachtable 'truncate table ?'

这将创建一个与您的“源”数据库相同的数据库,名为“source_test”。所有触发器、约束、存储过程、SQL Server 帐户以及不是数据表内容或序列号的所有其他数据位都被保留。当它们的表被截断时,所有的序列号将被重置为默认值。

我们使用这 5 个步骤来克隆我们自己的 SQL Server 数据库以用于测试和其他用途。这适用于 SQL Server 2000 向前。

要备份数据库,请按以下形式执行 SQL 语句:

"Backup database " + kstrDbName + " to disk = '" + strFullyPathedBackupFile + "' With Init";

“With Init”是一个关键选项,它告诉 SQL Server 覆盖指定的文件(如果存在)。有关“备份数据库”的 SQL Server 文档,可以找到更多信息。

在 SQL Server 2005 和更高版本上,您可以使用 SMO 恢复数据库,并指定数据库的新名称,以及重命名数据库文件(mdf 和日志文件)。有关如何执行此操作的示例代码,请参阅有关还原功能的 Microsoft SQL Server SMO 文档。

在 SQL Server 2000 上,没有 SMO 支持,因此必须通过执行 SQL 语句手动完成。这采用类似于以下形式的语句:

    string strSQL = "Restore database " + strDatabaseName + "from disk = '" + strSourcePathFile + "' with replace, " +
            " Move '" + strDatabaseName + "_Data' to '" + strDestinationPathFile + ".MDF', " +
            " Move '" + strDatabaseName + "_Log' to '" + strDestinationPathFile + ".LOG' " 

然后使用 Alter 语句重命名实际的 MDF 和 LOG 文件以匹配新名称。是的,这意味着在 SQL Server 2000 上,您不能拥有源数据库和目标数据库。对不起。可能可以在还原的同时重命名 MDF 和 LOG 文件,但如果是这样,我的团队无法让它工作。我们已经转移到新的 SQL Server 数据库,但我想我会为了这个答案的完整性提取旧代码。

alter 语句的形式为:

    string AlterDbSQL = " Alter database " + strDatabaseName + " MODIFY FILE(NAME = " + Path.GetFileNameWithoutExtension( strDestinationPathFile ) + "_DATA, NEWNAME = " + strDatabaseName + "_Data) " +
                        " Alter database " + strDatabaseName + " MODIFY FILE(NAME = " + Path.GetFileNameWithoutExtension( strDestinationPathFile ) + "_LOG, NEWNAME = " + strDatabaseName + "_LOG) "

一些注意事项:如果您感兴趣的只是创建一个测试数据库,那么您不需要每次都执行第 2 步(连接到源)和第 3 步(创建备份)。只需创建一个备份,还原它,然后截断表,即可为您要测试的当前数据库创建一个“模板”备份。备份该数据库。现在您已经备份了数据库的数据内容清除版本。这将是一个较小的备份,因此复制速度更快,恢复速度也更快。您需要做的就是添加您的测试数据,然后就可以进行测试了。

【讨论】:

    【解决方案2】:

    遗憾的是,我们发现的最自动化的过程实际上是使用其中一种鼠标控制工具来实际使用 SSMS 来复制数据库。我宁愿做其他事情,但没有一个答案真正符合我们的要求。

    【讨论】:

      【解决方案3】:

      如果您想要一份完整的副本,其他答案很有效,但您可能会感兴趣的另一种方法。如果您使用的是 LINQ to SQL,您可以创建一个 DBML 文件,然后在您的数据上下文中使用 CreateDatabase() 方法。它不会复制整个模式(省略一些约束、UDF、Procs 等),但在您可能希望对表进行操作并可能对数据库测试进行分区的场景中很有用。

      这里有几个步骤:

      1. 创建一个 Windows 窗体应用程序

      2. 创建一个名为 Foo 的 DBML 文件(LINQ to SQL 类)

      3. 将您感兴趣的表格/对象拖到设计界面

      4. 关闭/保存

      5. 在您的应用程序中的某些地方,您可以编写如下代码:

        FooDataContext fooData = new FooDataContext(@"连接到新数据库的字符串");

        fooData.CreateDatabase();

      Here 是我上面描述的方法的文档。

      【讨论】:

        【解决方案4】:

        如果您在 2005 年查看 DMO - 数据库管理对象,您不会说您使用的是哪个版本的 SQL Server,这是一组 COM 库,可让您访问 Enterprise Manager/Management Studio 中的功能。

        对于 2008 年,我们有 SMO 类似的功能,但作为 .Net 程序集,MS 有一些 good code examples。他们的脚本示例看起来像您需要的那样:-

        我们已经从他们的网站上删除了

        //Connect to the local, default instance of SQL Server. 
        { 
           Server srv = default(Server); 
           srv = new Server(); 
           //Reference the AdventureWorks database. 
           Database db = default(Database); 
           db = srv.Databases("AdventureWorks"); 
        
           //Define a Scripter object and set the required scripting options. 
           Scripter scrp = default(Scripter); 
           scrp = new Scripter(srv); 
           scrp.Options.ScriptDrops = false; 
           scrp.Options.WithDependencies = true; 
        
           //Iterate through the tables in database and script each one. Display the script. 
           //Note that the StringCollection type needs the System.Collections.Specialized namespace to be included. 
           Table tb = default(Table); 
           Urn[] smoObjects = new Urn[2]; 
           foreach ( tb in db.Tables) { 
              smoObjects = new Urn[1]; 
              smoObjects(0) = tb.Urn; 
              if (tb.IsSystemObject == false) { 
                 StringCollection sc = default(StringCollection); 
                 sc = scrp.Script(smoObjects); 
                 string st = null; 
                 foreach ( st in sc) { 
                    Console.WriteLine(st); 
                 } 
              } 
           } 
        } 
        

        【讨论】:

        • 注意:这不会创建除了表格之外的任何东西;我们需要用户、存储过程、视图、用户定义类型等。
        【解决方案5】:

        【讨论】:

        • 嗯,问题是第一个不能做,因为我们没有数据库脚本,第二个不能自动化。
        猜你喜欢
        • 2011-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-31
        • 2012-03-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多