web-dev-qa-db-ja.com

SQLサーバーの日付時刻フィールドを変換して、日付の部分のみを比較し、インデックス付きのルックアップを使用する

私はSQLサーバーの「間」クエリで使用している各日付フィールドでconvert(varchar,datefield,112)を実行して、日付のみを考慮し、時間部分に基づいて欠落していないことを確認しました日時フィールド。

今、私は、変換がインデックス付け可能ではなく、クエリ内の日付時刻の日付部分を比較して日付が範囲内にあるかどうかを判断するより良い方法があると聞いています。

このようなことを行う最適な、インデックス付け可能な方法は何ですか:

select * from appointments
where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'
28
Caveatrob

数値型を文字列値(ボクシングの一種)に変換することは、探していることを行うのに最適な方法ではありません。実際の列タイプは日時であるため、実際には索引付け可能というわけではありません。

日付の最良の方法のクエリを探している場合、あなたの例は正しいですが、MSSQLの3ミリ秒の精度の違いを考慮したいかもしれません。これは、ある日の記録が別の日の結果に表示されることを意味します。

この

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'

これであるべき

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<='08-14-2008 23:59:59.996'
5
StingyJack

日時フィールドの時刻部分を削除する最良の方法は、datediffおよびdateadd関数を使用することです。

   DateAdd(day, datediff(day,0, MydateValue), 0)

これは、SQL Serverが日付を2つの整数として格納するという事実を活用します。1つは1日目「0」からの日数1 1 Jan 1)を表し、2つ目は---(ticks(各ティックは約3.33ミリ秒)真夜中(時間)*以降。

上記の式は、最初の整数を読み取るだけで済みます。変換や処理は必要ないため、非常に高速です。

クエリでインデックスを使用するには...まずクエリオプティマイザーが計算を実行する必要がないように、入力フィルタリングパラメーターでこの式を使用するか、テーブルの日付時刻フィールドの等号の「その他」側でこの式を使用しますテーブルのすべての日時フィールドで、フィルター述語を満たす行を決定します。これにより、検索引数が「SARG対応」になります(検索ARGument)

Where MyDateTimeColumn > DateAdd(day, 
      datediff(day,0, @MydateParameter), 0)    -- SARG-able

のではなく

Where DateAdd(day, datediff(day,0, 
      MyDateTimeColumn ), 0) > @MydateParameter -- Not SARG-able

* 注意。内部的に、2番目の整数(時間部分)はティックを格納します。 1日には24 x 60 X 60 X 300 = 25,920,000ティック(偶然にも32ビット整数が保持できる最大値のすぐ下)です。ただし、日付時刻を算術的に変更する場合、これについて心配する必要はありません...日付時刻から値を加算または減算する場合、まるで1日の小数部に等しいかのように値を小数部として扱うことができます。完全な日時値は、日付を表す整数部分と時刻を表す小数部分で構成される浮動小数点数でした)。すなわち、

`Declare @Dt DateTime  Set @Dt = getdate()  
 Set @Dt = @Dt + 1.0/24  -- Adds one hour  
 Select @Dt  
 Set @Dt = @Dt - .25 -- Moves back 6 hours  
 Select @Dt`
66
Charles Bretana

正しいです-変換を行うと、クエリされたすべての行に対して変換が実行されます。日付列を日付のままにして、where句を日付として渡すことをお勧めします。

select * from appointments where appointmentdate between 
'08/01/2008' AND '08/16/2008'

注:時間を省略すると、真夜中(00:00.000)を意味するため、08/01のすべての時間、08/15のすべての時間、および2008/08/16の正確な時間をすべて含めます。

2
Kieveli

計算された永続列に必要な式を計算させます。列が計算されて永続化される場合、列にインデックスを付けることもできます。

1
devio

http://www.stillnetstudios.com/comparing-dates-without-times-in-sql-server/ で説明されている方法もあります

SELECT CAST(FLOOR(CAST( getdate() AS float )) AS datetime)
0