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

我正在使用SQL 2008数据库项目(在Visual Studio中)来pipe理我的项目的模式和初始testing数据。 atabase项目使用后期部署,其中包含许多使用SQLCMD“:r”语法的其他脚本。

我希望能够有条件地包含某些基于SQLCMDvariables的文件。 这将使我可以在我们每晚构build中多次运行项目,以使用不同的数据configuration(对于多租户系统)来设置各种版本的数据库。

我已经尝试了以下内容:

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

有没有人看到这个错误,或设法configuration他们的postdeployment脚本是灵活的这种方式? 还是我完全用错误的方式来解决这个问题?

谢谢,罗布

PS我也试着改变这个,所以文件的path是一个variables, 类似于这篇文章 。 但是这给了我一个错误,说道路是不正确的。

UPDATE

我现在发现上面的if / else语法不适用于我,因为我的一些链接脚本需要一个GO语句。 本质上:r只是直接导入脚本,所以这成为无效的sytax。

如果你需要在链接的脚本中使用GO语句(就像我这样做),那么没有任何简单的方法可以解决这个问题,我最终创build了几个post部署脚本,然后改变我的项目以在构build时覆盖主要部署depployment脚本在构buildconfiguration。 这正在做我所需要的,但似乎应该有一个更简单的方法!

对于任何需要同样的事情 – 我觉得这个职位很有用

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

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

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

  <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> 

最后,您需要在解决scheme中设置匹配的构buildconfiguration。

另外,对于任何尝试其他工作的人来说,我也尝试了以下方法,没有任何运气:

  1. 创build后期构build事件来复制文件,而不是必须破解项目文件XML。 我无法得到这个工作,因为我不能形成后部署脚本文件的正确path。 这个连接问题描述了这个问题

  2. 使用脚本path的variables传递给:r命令。 但是我用这种方法遇到了一些错误。

以下是我在部署后stream程中如何处理条件部署以部署Debug而不是Releaseconfiguration的testing数据。

首先,在解决scheme资源pipe理器中,打开项目属性文件夹,然后右键单击以添加一个新的SqlCmd.variables文件。

命名文件Debug.sqlcmdvars

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

重复该过程来创buildRelease.sqlcmdvars,将$(BuildConfiguration)为Release。

现在,configuration您的configuration:打开项目属性页面到部署选项卡。 在最上面的下拉列表中,将configuration设置为Debug。 在底部的下拉列表中,(Sql命令variables),将该文件设置为Properties \ Debug.sqlcmdvars。

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

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

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

在解决scheme资源pipe理器中,右键单击顶级解决scheme并打开configurationpipe理器。 您可以指定哪个configuration对于​​您的构build是活动的。 您也可以在MSBUILD.EXE命令行上指定configuration。

现在你去 – 现在你的开发人员构build有testing数据,但不是你的发布版本!

我设法解决了使用noexec方法的问题。

所以,而不是这个:

 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 

如果要执行任何后续的语句,请确保将其closures。

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

不过,我有一个不同的解决scheme – 如果可能的话,从引用的脚本中删除任何GO语句,并在END语句之后放置一个:

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

请注意,我还在我的sqlcmdvars文件中创build了一个名为$(DeployTestData)的新variables,它允许我打开/closurestesting脚本部署。

我发现从MSDN博客黑客工作得很好。 诀窍是将命令写入临时脚本文件,然后执行该脚本。 基本上相当于SQLCMD的dynamicSQL。

 -- 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语句等没有问题。

我受到了Rob Bird解决scheme的启发。 不过,我只是使用生成事件来replace基于选定的生成configuration的后部署脚本。

  1. 我有一个空的“虚拟”后部署脚本。
  2. 我设置了一个预生成事件来根据所选的构buildconfiguration来replace这个“虚拟”文件(参见附图)。
  3. 在构build完成之后,我设置了一个构build后事件来放置“虚拟”文件(参见附图)。 原因是我不想在构build之后在更改控件中生成更改。

构建事件设置示例