8

私は SQL Server 2000 で T-SQL を使用しており、この質問に関係のない他の多くの列の中で、DateTime として定義されTRANSACTIONSた日付列を持つテーブルがあります..TRANDATE

テーブルには、何年にもわたるトランザクションが入力されています。私は混乱しているコード、テストに出くわしました。SELECT次のような単純なものがあります。

SELECT TRANDATE, RECEIPTNUMBER FROM TRANSACTIONS WHERE TRANDATE BETWEEN '12/01/2010' and '12/31/2010' ORDER BY TRANDATE

そのテーブルにあることがわかっている2行のデータが返されません。

上記のステートメントでは、返される最後の行は、順番に次のようになりますTRANDATE: 2010-12-31 00:00:00.000

以下のようにステートメントを変更すると、そのテーブルにある 2010 年 12 月の追加の 2 行が取得されます。

SELECT TRANDATE, RECEIPTNUMBER FROM TRANSACTIONS WHERE TRANDATE BETWEEN '12/01/2010 00:00:00' and '12/31/2010 23:59:59' ORDER BY TRANDATE

上記BETWEENの最初SELECTの . SELECTまた、正しい行数を取得するために、2 番目の変更されたステートメントのように、ステートメントに明示的な時間を追加する必要があるのはなぜでしょうか?

方法TRANDATEが「 」と定義されているためDATETIMEでしょうか。

この発見に基づいて、これらのBETWEENオペレーターはこの古いシステム全体に散らばっており、すべてのデータを適切にプルしていないように見えるため、この古いコードをすべて実行する必要があると思います。最初に何人かの人々からの説明が欲しかっただけです。ありがとう!

4

5 に答える 5

14

日付は、期間ではなく、特定の時点です。

'12/31/2010'もポイントです。つまり、12 月 31 日の真夜中です。
この時点以降に発生したことはすべて無視されます。
それはまさにあなたが望む動作です (まだ気付いていなくても)。

時刻の部分を省略した場合、魔法のように と見なされるとは思わないでください"any""all zeroes"真夜中です。

指定せずに 1 日全体をクエリに含めたい場合23:59:59(ちなみに、当日の瞬間と翌日の瞬間の間の最後の 1 秒は除外されます)、それを行うことができます。厳密な不等式 ( , ) を使用して、不要な最初の時点で境界を設定します。 23:59:59 00:00:00><

WHERE TRANDATE >='12/01/2010 00:00:00' and TRANDATE < '01/01/2011'

またはキャストされた日付値を比較することによってDATE:

WHERE CAST(TRANDATE AS DATE) between '12/01/2010' and '12/31/2010'

(このタイプのキャストをWHERE節に入れても問題ありません。それは sargable です)。

于 2011-03-25T14:53:06.280 に答える
4

お気づきのように、日付を入力するときに時刻を指定しないと、デフォルトで日付の午前 0 時になります。したがって、2010 年 12 月 31 日は、その日が始まる午前 0 時に停止します。

2010 年 12 月 31 日のすべての日付を取得するには、これまでのように時刻を指定するか、終了日に 1 日を追加します。時刻がない場合、2011 年 1 月 1 日は 2010 年 12 月 31 日の午前 0 時に終了します。だから、あなたはすることができますBETWEEN 12/1/2010 AND 1/1/2011DATEADDそれが簡単になる場合は、SQL に日を追加するために使用できます。

1 日を追加するという 2 番目のアプローチには、ある程度のリスクがあります。時刻が 00:00:00 である 2011 年 1 月 1 日のレコードがすべて取得されます。

を実行する 1 つの方法を次に示しDATEADDます。

DECLARE @FromDate datetime, @ToDate datetime
// These might be stored procedure input parameters
SET @FromDate = '12/1/2010'
SET @ToDate = '12/31/2010'

SET @ToDate = DATEADD(d, 1, @ToDate)

次に、通常の方法で句の句で使用@ToDateします。WHEREBETWEEN

于 2011-03-25T14:55:16.213 に答える
3

「12/01/2010」は「12/01/2010 00:00:00」を意味し、「12/31/2010」は「12/31/2010 00:00:00」を意味します。これが、2010 年 12 月 31 日以降の日時の値がクエリ結果から除外される理由です。

于 2011-03-25T14:53:19.593 に答える
2

私がこれを行うとしたら、どのような結果が期待されますか

Insert "12/31/2010" into your datetime column?

正確には: 12-31-2010 00:00:00

では、クエリの引数として異なることを期待するのはなぜですか?

于 2011-03-25T14:52:44.890 に答える
1

あなたはすでにあなた自身の質問に答えています。あなたが観察したの、SQL Server の仕組みです。

確認が必要な場合は、このMSDN ドキュメントに次のように記載されています。

時間部分が指定されていない場合、デフォルトは午前 12:00 になります。1998 年 0105 日の午前 0 時以降の時間部分を含む行は、範囲外であるため、このクエリでは返されないことに注意してください。

編集

あなたのコメントに関しては、日時は本質的に浮動小数点値です。

次のスクリプトは、SQL Server が処理する数値を示しています。
上限が 40541 (12/31/2010) の場合、40541.9749 (12/31/2010 23:23:59) を含めることはできません

DECLARE @ADateTime1 DATETIME
DECLARE @ADateTime2 DATETIME
DECLARE @ADateTime1AsFloat FLOAT
DECLARE @ADateTime2AsFloat FLOAT

SET @ADateTime1 = '12/31/2010'
SET @ADateTime2 = '12/31/2010 23:23:59'

SET @ADateTime1AsFloat = CAST(@ADateTime1 AS FLOAT)
SET @ADateTime2AsFloat = CAST(@ADateTime2 AS FLOAT)

SELECT @ADateTime1AsFloat, @ADateTime2AsFloat
于 2011-03-25T14:52:50.513 に答える