仮定する
isnull(some_column, getdate()) >= getdate()
ここでのロジックは、some_column が null の場合、この式は常に true である必要があります。ただし、これは常にそうでしょうか (getdate() の 2 つの評価の間に時間が経過し、それらが等しくならないため) ?
仮定する
isnull(some_column, getdate()) >= getdate()
ここでのロジックは、some_column が null の場合、この式は常に true である必要があります。ただし、これは常にそうでしょうか (getdate() の 2 つの評価の間に時間が経過し、それらが等しくならないため) ?
いいえ、安全ではありません。いわゆるランタイム定数式に直面しています。これGETDATE()
は本棚の例であり、クエリの起動時に一度評価され、その後キャッシュされた評価値が使用されます。ただし、各オカレンスは個別に 1 回評価され、2 つの評価が datetime 精度境界の別々の側にある可能性があり、結果として 2 つの異なる値が得られます。
簡単なテストで、これがどのように発生するかが明らかになります。
declare @cnt int = 0, @i int = 0
while @cnt = 0
begin
select @cnt = count(*)
from master..spt_values
where getdate() != getdate();
set @i += 1;
if @cnt != 0
raiserror(N'@cnt = %d this shoudl not happen but it dit after @i = %d', 16, 1, @cnt, @i);
end
私の場合、これはすぐにヒットしました:
Msg 50000, Level 16, State 1, Line 9
@cnt = 2515 this shoudl not happen but it dit after @i = 694
これをより適切に行う方法については触れていませんが (すでに多くのアドバイスをいただいています)、実行時の実行に関する仮定が正しいかどうか (そうではない) の根底にある質問は次のとおりです。
GETDATE()
ステートメント内の 2 回は 2 回評価されます
条件で true を探しているので、getDate()
2 回使用する必要はありません。代わりに非常に大きな日付を入れてください...
例えば:
isnull(some_column, '2999-01-01') >= getDate()
のように
declare @some_column(datetime)
select case when isnull(@some_column,'2999-01-01') >= getdate() then 1 else 0 end
これは 1 を返します。
または、適切に実行して null を明示的に確認することもできます。
(some_column >= getdate() or some_column is null)
SQL Server 2000 以前のバージョンでは、getdate() は、SQL 文ごとに 1 回評価される決定論的関数です。2005 年以降、getdate は決定論的ではなく、毎回評価されるため、値を変数に割り当てる必要があります。
2 回呼び出しているためGETDATE()
、これは失敗する可能性がありますが、ほとんどの場合は正しく機能します。
軽減するには、次のことを実行できます。
DECLARE currentDate DATETIME
SELECT currentDate = GETDATE()
isnull(some_column, currentDate) >= currentDate
なぜあなたは日付を使いたいのですか?つまり、デフォルトの真の条件を評価/処理するようにSQLサーバーに依頼する理由はありません。代わりに使用できます
isnull(some_column, 2) >= 1