使用SQLCMD的PostDeployment.sql脚本中的条件逻辑

时间:2011-08-22 17:15:55

标签: sql database sql-server-2008 sqlcmd

我正在使用SQL 2008数据库项目(在visual studio中)来管理项目的架构和初始测试数据。 atabase项目使用后期部署,其中包含使用SQLCMD的“:r”语法的许多其他脚本。

我希望能够有条件地包含基于SQLCMD变量的某些文件。这将允许我使用我们的每晚构建多次运行项目,以使用不同的数据配置设置各种版本的数据库(对于多租户系统)。

我尝试了以下内容:

IF ('$(ConfigSetting)' = 'Configuration1')
  BEGIN
    print 'inserting specific configuration' 
:r .\Configuration1\Data.sql
  END
ELSE
  BEGIN
    print 'inserting generic data' 
:r .\GenericConfiguration\Data.sql
  END

但是我收到了编译错误: SQL01260:发生了致命的解析器错误:Script.PostDeployment.sql

有没有人看到过这个错误或设法将他们的postdeployment脚本配置为这样灵活?还是我完全以错误的方式解决这个问题?

谢谢, 罗布

P.S。我也试过更改它,以便文件的路径是变量similar to this post。但这给了我一个错误,说路径不正确。

6 个答案:

答案 0 :(得分:35)

<强>更新

我现在发现上面的if / else语法对我不起作用,因为我的一些链接脚本需要一个GO语句。基本上:r只是内联导入脚本,因此这将成为无效的sytax。

如果您需要链接脚本中的GO语句(就像我一样)那么没有任何简单的方法,我最终创建了几个后期部署脚本,然后更改我的项目以覆盖主要的后部署部署脚本构建时间取决于构建配置。现在正在做我需要的事情,但似乎应该有一个更简单的方法!

对于需要同样事情的人 - I found this post useful

所以在我的项目中,我有以下帖子部署文件:

  • Script.PostDeployment.sql(将被替换的空文件)
  • Default.Script.PostDeployment.sql(链接到标准数据配置所需的脚本)
  • Configuration1.Script.PostDeployment.sql(链接到特定数据配置所需的脚本)

然后我将以下内容添加到项目文件的末尾(右键单击以卸载然后右键单击编辑):

  <Target Name="BeforeBuild">
      <Message Text="Copy files task running for configuration: $(Configuration)" Importance="high" />
      <Copy Condition=" '$(Configuration)' == 'Release' " SourceFiles="Scripts\Post-Deployment\Default.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
      <Copy Condition=" '$(Configuration)' == 'Debug' " SourceFiles="Scripts\Post-Deployment\Default.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
      <Copy Condition=" '$(Configuration)' == 'Configuration1' " SourceFiles="Scripts\Post-Deployment\Configuration1.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
  </Target>

最后,您需要在解决方案中设置匹配的构建配置。

此外,对于任何尝试其他工作的人,我也试过以下没有任何运气:

  1. 创建post build事件以复制文件,而不必破解项目文件XML。我无法使其工作,因为我无法形成部署后脚本文件的正确路径。 This connect issue describes the problem

  2. 使用脚本路径的变量传递给:r命令。但是我遇到了这种方法的几个错误。

答案 1 :(得分:16)

我设法使用noexec method处理问题。

所以,而不是:

IF ('$(ConfigSetting)' = 'Configuration1')
 BEGIN
    print 'inserting specific configuration' 
    :r .\Configuration1\Data.sql
 END

我颠倒了条件并将 NOEXEC ON 设置为跳过导入的语句:

IF ('$(ConfigSetting)' <> 'Configuration1')
    SET NOEXEC ON

:r .\Configuration1\Data.sql

SET NOEXEC OFF

如果您想执行任何后续声明,请务必将其关闭。

答案 2 :(得分:15)

以下是我在部署后流程中处理条件部署的方式,以便为Debug而不是Release配置部署测试数据。

首先,在solution explorer中,打开项目属性文件夹,然后右键单击以添加新的SqlCmd.variables文件。

将文件命名为Debug.sqlcmdvars

在文件中,添加自定义变量,然后添加名为$(BuildConfiguration)的最终变量,并将值设置为Debug。

重复此过程以创建Release.sqlcmdvars,将$(BuildConfiguration)设置为Release。

现在,配置您的配置: 打开项目属性页面到Deploy选项卡。 在顶部下拉列表中,将配置设置为Debug。 在底部下拉列表(Sql命令变量)中,将文件设置为Properties \ Debug.sqlcmdvars。

重复发布为: 在顶部下拉列表中,将配置设置为Release。 在底部下拉列表(Sql命令变量)中,将文件设置为Properties \ Release.sqlcmdvars。

现在,在Script.PostDeployment.sql文件中,您可以指定条件逻辑,例如:

IF 'Debug' = '$(BuildConfiguration)'
BEGIN
PRINT '***** Creating Test Data for Debug configuration *****';
:r .\TestData\TestData.sql
END

在解决方案资源管理器中,右键单击顶级解决方案并打开配置管理器。您可以指定构建的活动配置。 您还可以在MSBUILD.EXE命令行上指定配置。

你去 - 现在你的开发者构建有测试数据,但不是你的发布版本!

答案 3 :(得分:8)

正如Rob所做的那样,链接的SQL脚本中不允许使用GO语句,因为这会将它嵌套在BEGIN / END语句中。

但是,我有一个不同的解决方案 - 如果可能的话,从引用的脚本中删除任何GO语句,并在END语句后面添加一个:

IF '$(DeployTestData)' = 'True'
BEGIN
    :r .\TestData\Data.sql
END
GO -- moved from Data.sql

请注意,我还在名为$(DeployTestData)的 sqlcmdvars 文件中创建了一个新变量,它允许我打开/关闭测试脚本部署。

答案 4 :(得分:2)

我发现hack from an MSDN blog效果相当好。诀窍是将命令写入临时脚本文件,然后执行该脚本。基本上相当于SQLCMD的动态SQL。

-- Helper newline variable
:setvar CRLF "CHAR(13) + CHAR(10)"
GO
-- Redirect output to the TempScript.sql file
:OUT $(TEMP)\TempScript.sql

IF ('$(ConfigSetting)' = 'Configuration1')
  BEGIN
    PRINT 'print ''inserting specific configuration'';' + $(CRLF)   
    PRINT ':r .\Configuration1\Data.sql' + $(CRLF)
  END
ELSE
  BEGIN
    PRINT 'print ''inserting generic data'';' + $(CRLF) 
    PRINT ':r .\GenericConfiguration\Data.sql' + $(CRLF)
  END
GO
-- Change output to stdout
:OUT stdout

-- Now execute the generated script
:r $(TEMP)\TempScript.sql
GO

TempScript.sql文件将包含:

print 'inserting specific configuration';   
:r .\Configuration1\Data.sql

print 'inserting generic data';
:r .\GenericConfiguration\Data.sql

取决于$(ConfigSetting)的值,执行时GO语句等不会出现问题。

答案 5 :(得分:2)

我受到Rob Bird的解决方案的启发。但是,我只是使用构建事件来替换基于所选构建配置的后部署脚本。

  1. 我有一个空的&#34;假的&#34;发布部署脚本。
  2. 我设置了一个预构建事件来替换这个&#34; dummy&#34;基于所选构建配置的文件(参见附图)。
  3. 我设置了一个post-build事件来放置&#34; dummy&#34;构建完成后返回文件(参见附图)。原因是我不希望在构建之后在更改控件中生成更改。
  4. Build Events setup example