0

我想编写一个接受 aDATETIME2并返回 a的 SQLCLR UDF DATETIME2。输入和输出应该允许 NULL。

我创建了一个 SQL Server 数据库项目 (SSDT),在其 SQLCLR 属性中将其配置为 VB 语言,然后添加以下文件Test.vb

Option Explicit On
Option Strict On

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server

Partial Public Class UserDefinedFunctions
    <SqlFunction()> _
    Public Shared Function Test(d As Nullable(Of DateTime)) As Nullable(Of DateTime)
        Return d
    End Function
End Class

从 SQL Server 2008 开始,http: //msdn.microsoft.com/en-us/library/ms131092 (v=SQL.100).aspx似乎支持以这种方式使用 nullable 。

但是,当我运行部署命令时,出现以下错误:

SQL46010: ) 附近的语法不正确。

这是因为它生成的 SQL 是:

CREATE FUNCTION [dbo].[Test] (@d /* Error: Unsupported type. */)
RETURNS /* Error: Unsupported type. */
    AS EXTERNAL NAME [Test].[Test.UserDefinedFunctions].[Test];

我无法替代SqlDateTime,因为我需要DATETIME2.

4

2 回答 2

0

看看这个。SqlDateTime 允许空值,因此能够通过类的属性检查值是否为空。

于 2012-12-26T17:53:02.367 回答
0

问题出在 SSDT(SQL Server Data Tools)而不是 SQLCLR。是的,SQLCLR 确实支持DATETIME2via DateTime?/ Nullable<DateTime>。不幸的是,SSDT(我正在使用 VS2013 和 SSDT v 12.0.50512.0)尚不(我在这里很乐观,我知道)支持DATETIME2DateTimeor 或DateTime?. 但是,像以前一样使用它也不会出错DateTime?。尽管如此,要么 要么DateTime将在生成的 SQL 中DateTime?显示为常规。DATETIME

我不确定告诉 SSDT 数据类型应该是什么的任何真正“适当”的方法。实际上有相当多的选项是不受支持的,包括通用的 UDF 选项WITH RETURNS NULL ON NULL INPUT和参数选项,例如默认值。这是可悲和令人沮丧的,是的。

到目前为止,我想出的最好的方法(我仍在寻找其他选项)是ALTER使用所需选项将部署后脚本添加到函数的定义中:

  1. PROJECT菜单中,选择Add New Item...(VS2013 中的Control+ Shift+ )A
  2. 转到SQL Server ->用户脚本
  3. 选择部署后脚本
  4. 给它一个名称(名称本身并不能确定它是预部署、部署后还是两者都不是;它只需要以.sql结尾)并单击Add
  5. 您将被置于(大部分)空 SQL 脚本中
  6. 输入一个或多个ALTER语句,类似于以下内容:

    -- declare once
    DECLARE @ObjectName sysname; -- keep lower-case to work in case-sensitive collations
    
    SET @ObjectName = N'Test';
    
    IF (EXISTS(
                SELECT  *
                FROM    sys.assembly_modules sam
                WHERE   sam.[object_id] = OBJECT_ID(@ObjectName)
            )
        )
    BEGIN
        PRINT 'Checking custom properties for [' + @ObjectName + N']...';
    
        IF (EXISTS(
                    SELECT  *
                    FROM    sys.parameters sp
                    INNER JOIN  sys.types st
                            ON  st.system_type_id = sp.system_type_id
                    WHERE   sp.[object_id] = OBJECT_ID(@ObjectName)
                    AND     st.[name] <> N'datetime2' -- keep lower-case to work in
                                                      -- case-sensitive collations
                )
        )
        BEGIN
            PRINT 'Setting custom properties for [' + @ObjectName + N']...';
    
            BEGIN TRY
                EXEC('
    ALTER FUNCTION [dbo].[Test](@d [datetime2])
    RETURNS [datetime2] WITH EXECUTE AS CALLER
    AS EXTERNAL NAME [Test].[Test.UserDefinedFunctions].[Test];
                ');
            END TRY
            BEGIN CATCH
                DECLARE @ErrorMessage NVARCHAR(4000);
                SET @ErrorMessage = ERROR_MESSAGE();
                RAISERROR(@ErrorMessage, 16, 1);
                RETURN;
            END CATCH;
        END;
    
    END;
    ELSE
    BEGIN
        RAISERROR(N'Oops. [%s] was renamed or no longer exists!', 16, 1, @ObjectName);
        RETURN;
    END;
    
    ---
    
    SET @ObjectName = N'NextObjectToFix';
    -- copy the rest from above
    

此部署后脚本将始终包含在_Create发布/增量构建脚本的末尾。因此需要额外的逻辑来查看更改是否已经存在。确实,始终运行 .通常并没有什么坏处ALTER,但在极少数情况下,该对象是其他对象的依赖项,例如 Check Constraint 或 Computed Column,除非需要更改,否则最好不要理会它.

您可以从脚本(只需将 更改为)或在 SSMS 中获得正确的ALTER定义,如果您右键单击对象并选择Modify。在这两种情况下,更改数据类型和任何其他选项(显然 ;-)。\bin\Configuration\*_Create.sqlCREATEALTER


另一个有点相关的想法是不依赖于 T-SQL 包装对象CREATE语句的 Visual Studio / SSDT 发布过程,而仅使用它来管理程序集。在此设置中,您将取消选中Project Properties的SQLCLR选项卡上的Generate DDL选项。然后,您将添加一个部署后脚本(如上面的建议中所述)并放入您自己的,等语句。CREATE FUNCTION ...CREATE PROCEDURE ...

对于初始开发来说,引入新对象并不像使用 SSDT 生成 DDL 那样快速和容易,但考虑到新对象的创建并不频繁,而且它们的签名更改频率要低得多,因此真正自己管理这个 DDL还不错(事实上,它与我用于包含 250 多个对象的SQL#库的过程非常相似。务实地说,一旦您拥有每个对象类型CREATE语句之一,您就可以复制和粘贴它们用于新对象并更改名称和参数等。这种方法需要的最多工作是在创建新 TVF 时,如果它返回一堆字段,但这并不是真正的工作,因为您必须输入同入TableDefinition财产SqlFunction如果您使用 SSDT 来管理 DDL 创建,则无论如何都要属性。

于 2015-08-18T04:45:40.937 回答