web-dev-qa-db-ja.com

列が非決定的であるため、テーブル<table_name>の計算列 'IsWeekend'を永続化できません

列でDATENAME()関数を使用してデータが週末であるか平日であるかを確認するときに、誤ったカーディナリティの推定が原因でtempdbに波及するSQL Server 2012でクエリを調整しています。関数を使用しているため、クエリは引数をとることができず、行数(推定1700、実際の38000)を誤って推定しています。

Where句は単純です。

WHERE DATENAME(WEEKDAY, vqc.DateRecorded) NOT IN ('Saturday', 'Sunday')

永続的な計算列を使用してからインデックスを作成することを望んでいました。

ALTER TABLE <table_name> ADD IsWeekend AS DATENAME(WeekDay, DateRecorded) PERSISTED;

ただし、エラーが発生します。

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

[〜#〜] bol [〜#〜] によると、多数の日付関数は非決定的であるため永続化できません。

これは、結果がサーバーセッションのLANGUAGEおよびDATEFORMAT設定に依存するためです。たとえば、式CONVERT(datetime、'30 listopad 1996 '、113)の結果は、文字列'30 listopad 1996'が異なる言語で異なる月を意味するため、LANGUAGE設定に依存します。同様に、式DATEADD(mm、3、 '2000-12-01')では、データベースエンジンはDATEFORMAT設定に基づいて文字列 '2000-12-01'を解釈します。

Stack Overflow に投稿されたCASEステートメントを使用してMONTH()関数のこの問題を回避する興味深い方法がありましたが、SET DATEFIRSTDATENAMEが原因でLANGUAGEに対してこれは機能しません設定。

クエリでカレンダーテーブルに参加し、そこから週末をフィルタリングする以外に、日付を週末にして永続化してインデックスを作成できるようにする方法はありますか?

それとも状況を複雑にしようとしていますか?

3
Mark Sinkinson

datediff1900-01-01、それはたまたま月曜日であり、modulo 75または6

create table D
(
  DateRecorded date,
  IsWeekend as cast(case when datediff(day, 0, DateRecorded) % 7 in (5, 6) 
                      then 1 
                      else 0 
                    end as bit) persisted
)

ところで、インデックスで使用するために計算列を永続化する必要はありません。

5
Mikael Eriksson