1

何かが足りないのか、気が抜けているのか教えてください

以下のクエリは、devidebyzeroエラーを生成します

DECLARE @Test TABLE(
        ID INT,
        Val FLOAT
)

INSERT INTO @Test SELECT 1, 0

;WITH   Grouped AS (
        SELECT  ID,
                Val,
                SUM(Val) OVER (PARTITION BY ID) TotalVal
        FROM    @Test
)
, Filtered AS (
        SELECT  *
        FROM    Grouped
        WHERE   TotalVal != 0
)
SELECT  *
FROM    Filtered
WHERE   Val / TotalVal > 0.05

SQLフィドルデモ

以下は同じエラーを生成しませんが

DECLARE @Test TABLE(
        ID INT,
        Val FLOAT
)

INSERT INTO @Test SELECT 1, 0

;WITH   Grouped AS (
        SELECT  ID,
                Val,
                SUM(Val) OVER (PARTITION BY ID) TotalVal
        FROM    @Test
)
, Filtered AS (
        SELECT  *
        FROM    Grouped
        WHERE   TotalVal != 0
)
SELECT  *,
        Val / TotalVal Test
FROM    Filtered

SQLフィドルデモ

推定されたクエリプランを見ると、最初のクエリはwhere句を次のように最適化しようとします。

[Val]/[Expr1004]>(5.000000000000000e-002) AND [Expr1004]<>(0.000000000000000e+000)

TotalVal != 0ここで、は実際の後にあることがわかりますdevide by TotalVal

これは既知の問題ですか?これを回避する方法はありますか(別の一時テーブルを使用する以外)。私はそれを使用してそれを行うことができることを知っています

CASE WHEN TotalVal = 0 THEN 0 ELSE Val / TotalVal END

しかし、それは2番目のCTEステートメントの目的を無効にします。

4

1 に答える 1

1

この接続項目に移動して、投票してください。

個人的には、SQL Server の動作に満足しています。なぜなら、後で計算するためにコンポーネントを繰り越すのではなく、式を事前に計算 (合理化) するためのある程度の最適化が可能になるからです (たとえ論理的に意味があるとしても)。

あなたのクエリに関しては、はい、Filtered CTE は非常に非イベントであり、最終的なクエリにロールする必要があります。そのように書くことは、CTE が何らかの形で処理され、メモリにキャッシュされていると信じていることを示唆しています。それは真実ではありません - this answer to another SO question を見てください。SQL Server の CTE 実装の詳細については、この記事を参照してください

于 2012-10-22T05:07:05.507 に答える