【问题标题】:Compile a function in an SSDT PreDeployment Script在 SSDT 预部署脚本中编译函数
【发布时间】:2021-11-18 16:23:45
【问题描述】:

我有一个不寻常的情况 - 第一次!

我正在尝试为 Visual Studio 中的 SSDT 项目编写一个部署前脚本,这将为迁移准备大量数据。在名为[MySchema].[MyFunc] 的新版本数据库中有一个用户定义的表值函数(TF),它对迁移脚本很有帮助……但它在旧数据库中尚不存在升级和迁移。新版本中还有很多其他的对象,但我只需要使用这一个来帮助迁移。该函数对任何其他新的(或现有的)对象没有任何依赖关系,它是完全独立的。

我希望将[MySchema].[MyFunc] 编译为预部署的一部分,以便我可以使用它。该函数位于.\MySchema\Functions\MyFunc.sql

我尝试了以下...

尝试 1

Incorrect syntax near CREATE 失败(注意:CREATE 是文件 .\MySchema\Functions\MyFunc.sql 的第一行):

IF object_id('[MySchema].[MyFunc]', 'TF') IS NULL
BEGIN
    :r .\MySchema\Functions\MyFunc.sql
END

尝试 2

Incorrect syntax near 'GO'Incorrect syntax near ':' Expecting CONVERSATION 失败:

GO
IF object_id('[MySchema].[MyFunc]', 'TF') IS NULL
BEGIN
    :r .\MySchema\Functions\MyFunc.sql
    GO
END

尝试 3

将整个 CREATE FUNCTION 语句复制并粘贴到我的预部署脚本中:

CREATE FUNCTION [MySchema].[MyFunc]
(
    @p1 VARCHAR(255)
)
RETURNS @returntable TABLE
(
    some_col NVARCHAR(MAX)
)
AS
BEGIN
    -- some function code here
    RETURN
END

但是CREATE FUNCTION must be the only statement in the batch 失败了。我尝试在此之前和之后插入 GO,但我得到了与 ATTEMPT 2 相似的结果。我也尝试使用 ; 而不是 GO

尝试 4

我尝试使用iTVF,但没有帮助

尝试 5

我考虑了一会儿,将代码从我的函数中取出并在没有函数的情况下使用它......但我需要在迁移脚本中使用该代码大约 20 次。所以我拒绝了这个选项。每次都会产生不同的结果(由于参数的变化),所以我不能把它放在 CTE 或类似的东西中,然后每次都重复使用。

请注意

答案应针对 SSDT 项目。这不是在 SSMS 中运行的代码。它在 Visual Studio 中,将作为Publish 进程的一部分运行。如果您不确定 SSDT 或预部署脚本是什么,请不要回答 :-) 任何不基于 SSDT 的答案都与这种情况无关。谢谢!

【问题讨论】:

  • ALTER/CREATE FUNCTIONALTER/CREATE PROCEDURE 需要是它们自己的单独批处理中的语句,即:您不能将它们包装在 IF 语句中。
  • 当我不得不走下那个兔子洞(将数据迁移到新架构中作为 SSDT 部署的一部分)时,我将所有迁移逻辑都放入了部署后脚本中。此时,您的功能将已经可用。
  • 当我不得不为一些迁移风格的脚本(尽管类似的概念)执行此操作时,我不得不将其重写为将创建函数的动态 SQL 调用。这样做很痛苦,但是对于将定期重复使用的东西,这是有道理的。因为这必须是批处理中的第一个命令,所以您可能需要查看使用动态 SQL 创建它的选项。或者,将您的部署包装在一个更大的脚本中,并在调用发布操作之前调用它。不好玩,但如果该函数尚不存在但被引用,则有时是必要的。

标签: sql-server visual-studio tsql sql-server-data-tools ssdt-2019


【解决方案1】:

如果您的目标是 SQL Server 2016 或更高版本,请想到两种可能的解决方案:

  1. 在包含您的功能代码之前,分批尝试:
DROP FUNCTION IF EXISTS [MySchema].[MyFunc];
  1. 修改MyFunc.sql 文件的内容,使其开头为:
CREATE OR ALTER FUNCTION [MySchema].[MyFunc]
...

参考资料:

【讨论】:

    【解决方案2】:

    您不能在 BEGIN/END 中使用 GO。我不明白为什么尝试 3 不起作用,很可能是因为您在同一脚本中拥有其他代码。通常您可以在预脚本中创建对象。根据 SQL Server 的版本,您可以使用 IF EXISTS 或将代码更改为 DROP 函数(如果存在),然后始终使用 CREATE 它而不是您尝试执行的相反方法。

    另一种方法是将数据填充逻辑简单地放入预脚本本身。您可以执行以下操作:

    IF NOT EXISTS (SELECT * FROM SomeTable)
    BEGIN
      INSERT INTO SomeTable ...
    END
    

    在这种情况下,您可以在不复制数据的情况下重新运行此脚本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-04
      • 2013-09-24
      • 1970-01-01
      • 2020-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多