0

DATETIME2を受け取り、を返す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

この方法での nullable の使用は、http://msdn.microsoft.com/en-us/library/ms131092(v=SQL.100).aspx ごとに SQL Server 2008 以降でサポートされているように見えます

ただし、デプロイ コマンドを実行すると、次のエラーが発生します。

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

問題は SSDT (SQL Server Data Tools) にあり、SQLCLR にはありません。はい、SQLCLR は実際に/DATETIME2経由でサポートしています。残念ながら、SSDT (私は VS2013 と SSDT v 12.0.50512.0 を使用しています) はまだ(私はここで楽観的です、私は知っています)またはからの推論をサポートしていません。しかし、以前のように使用してもエラーにはなりません。それでも、生成された SQL ではorが通常として表示されます。DateTime?Nullable<DateTime>DATETIME2DateTimeDateTime?DateTime?DateTimeDateTime?DATETIME

SSDTにデータ型がどうあるべきかを伝える真の「適切な」手段はわかりません。WITH RETURNS NULL ON NULL INPUTなどの一般的な UDF オプションや、デフォルト値などのパラメーター オプションなど、実際にはサポートされていないオプションがかなりあります。悲しくてもどかしいです、はい。

私がこれまでに思いついた最善の方法は (そして私はまだ他のオプションを検討しています) ALTER、目的のオプションを使用して関数の定義に配置後スクリプトを追加することです。

  1. プロジェクトメニューで、新しいアイテムの追加... ( VS2013 ではControl+ Shift+ ) を選択します。A
  2. SQL Server ->ユーザー スクリプトに移動します。
  3. 配置後スクリプトの選択
  4. 名前を付けて (名前自体は、デプロイ前、デプロイ後、またはそのどちらでもないかを判断しません。単に.sqlで終わる必要があります) をクリックします。Add
  5. (ほとんど) 空の SQL スクリプトに配置されます
  6. ALTER次のようなステートメントを 1 つ以上入力します。

    -- 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が、まれに、このオブジェクトがチェック制約や計算列などの他のものに依存している場合は、変更する必要がない限り、そのままにしておくのがおそらく最善です。 .

オブジェクトを右クリックして [変更] を選択すると、スクリプト ( を に変更するだけ)または SSMSから適切なALTER定義を取得できます。どちらの場合も、データ型とその他のオプションを変更します (明らかに ;-)。\bin\Configuration\*_Create.sqlCREATEALTER


CREATE多少関連するもう 1 つのアイデアは、T-SQL ラッパー オブジェクトステートメントの Visual Studio / SSDT パブリッシュ プロセスに依存せず、アセンブリの管理にのみ使用するというものです。この設定では、 Project PropertiesのSQLCLRタブにあるGenerate DDLオプションのチェックを外します。次に、Post Deployment スクリプトを追加し (上記の提案で説明したように)、独自の, などのステートメントを挿入します。CREATE FUNCTION ...CREATE PROCEDURE ...

最初の開発では、SSDT を使用して DDL を生成するよりも、新しいオブジェクトを導入するのが迅速かつ簡単ではありませんが、新しいオブジェクトが頻繁に作成されるわけではなく、署名が変更される頻度がはるかに低いことを考えると、この DDL を実際に自分で管理する必要があります。それほど悪くはありません (実際、 250 以上のオブジェクトを持つSQL#ライブラリに使用するプロセスと非常によく似ています。実用的に言えば、各オブジェクト タイプのCREATEステートメントを 1 つ取得したら、コピーして貼り付けるだけです。それらを新しいオブジェクト用に変更し、名前やパラメータなどを変更します。このアプローチが必要とする最も多くの作業は、一連のフィールドを返す場合に新しい TVF を作成するときですが、それを入力する必要があることを考えると、実際にはそれほど多くの作業ではありません。のTableDefinitionプロパティに同じSqlFunctionSSDT を使用して DDL の作成を管理していた場合は、とにかく属性を変更します。

于 2015-08-18T04:45:40.937 に答える
0

これを見てください。SqlDateTime は null を許可するため、クラスのプロパティを介して値が null かどうかを確認できます。

于 2012-12-26T17:53:02.367 に答える