15

計算列に対して次の関数があります。

CREATE FUNCTION [dbo].[GetAllocatedStartTime](@Year INT, @Week INT)
RETURNS DATETIME

WITH schemabinding
AS BEGIN
    RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT([varchar](4),@Year,(0))+'-01-01'),(1))))
END

GO

WITH schemabinding私はそれを永続化できるように決定論的にすることを期待して追加しました。これは 2 つの入力[Week]と同じである必要があり、[Year]常に同じ結果が得られます。

正確なエラーは次のとおりです。

テーブル 'Tmp_Bookings' の計算列 'AllocatedTimeStart' は、列が非決定論的であるため、永続化できません。

列でこの式を使用しています:

([dbo].[GetAllocatedStartTime]([Year],[Week]))

そして列 defs :

[Week] [int] NOT NULL,
[Year] [int] NOT NULL,
[AllocatedTimeStart]  AS ([dbo].[GetAllocatedStartTime]([Year],[Week])),

何か案は?

編集:

行を次のように変更:

RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)),(1))))

しかし、列の数式が無効であるというエラーが表示されます。関数は正常に保存されますが。

編集2:

私は自分がやっていることを正確に示しました(または少なくとも試しました)。本当に余分なものは何もありません。前の関数 (元の関数)[dbo].AllocatedStartDate(...)が列内の式参照と結合されていたが、永続的ではなかったと述べているように、それは非決定論的であると述べています。したがって、提案に従って、変換部分を新しいコードに置き換えて関数を変更したため、関数は次のようになります。

FUNCTION [dbo].[GetSTime](@Year INT, @Week INT)

RETURNS DATETIME
WITH schemabinding
AS BEGIN
    RETURN dateadd(week,@Week-(1),dateadd(day,(-1),dateadd(week,datediff(week,(0),CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)),(1))))
END

次に、計算フィールドで以前と同じ式を試しました(([dbo].[GetAllocatedStartTime]([Year],[Week])))...そして、式を拒否し、有効ではないと言います...式が同じであるため、これは奇妙です。変更されたものの何らかのチェックを行う必要があります関数とそれが無効であることがわかりました。これは、プレーンSELECT dbo.GetAllocatedStartTime(2012,13)を実行して機能したため、これも奇妙です...

はい、私は混乱しSqlFiddleています。気にしないで使用するのを見たことがありません。しかし、実際には、私が今言ったこと以上のものはありません。

4

1 に答える 1

22

CONVERT([varchar](4),@Year,(0))+'-01-01'DATEDIFF日付が期待される位置で呼び出しに渡され、暗黙的な変換が強制的に発生します。

決定論的関数のルールから:

CAST

datetimesmalldatetime、またはと一緒に使用しない限り、確定的sql_variantです。

CONVERT

次の条件のいずれかが存在しない限り、確定的:

...

ソースまたはターゲットの型がdatetimeまたはsmalldatetimeであり、もう一方のソースまたはターゲットの型が文字列であり、非決定論的スタイルが指定されています。決定論的であるためには、スタイル パラメーターは定数でなければなりません。さらに、スタイル 20 と 21 を除き、100 以下のスタイルは非決定論的です。スタイル 106、107、109、および 113 を除き、100 を超えるスタイルは決定論的です。

どちらも呼び出していませんが、暗黙の変換に依存していますCAST。これに頼るのではなくCONVERT、決定論的なスタイルのパラメーターを使用して指定することに切り替えます。

だから、私はそうします: CONVERT(datetime,CONVERT([varchar](4),@Year,(0))+'0101',112)その代わりに。そうすることで、関数自体が決定論的になります

于 2013-01-02T15:38:46.640 に答える