MS SQL Serverの「間」には範囲境界が含まれますか?


回答:


258

BETWEEN演算子は包括的です。

Books Onlineから:

BETWEENは、test_expressionの値がbegin_expressionの値以上で、end_expressionの値以下の場合にTRUEを返します。

日時の警告

注意:DateTimesでは注意が必要です。日付のみが指定されている場合、値はその日の真夜中の時点で取得されます。終了日の時間を逃したり、翌日のデータを複数の範囲で午前0時に繰り返し取得したりしないようにするには、終了日の日付を、当日の午前0時の3ミリ秒前にする必要があります。これとその値よりも小さい場合は3ミリ秒となり、値は翌日の真夜中に切り上げられます。

たとえば、2016年6月以内にすべての値を取得するには、次を実行する必要があります。

where myDateTime between '20160601' and DATEADD(millisecond, -3, '20160701')

すなわち

where myDateTime between '20160601 00:00:00.000' and '20160630 23:59:59.997'

datetime2およびdatetimeoffset

日付から3ミリ秒を引くと、3ミリ秒のウィンドウから行が欠落しやすくなります。正しい解決策も最も簡単なものです。

where myDateTime >= '20160601' AND myDateTime < '20160701'

11
BETWEENを使用して2つの日付の間のDateTimesをフィルターする場合、DateTimeを日付にキャストすることもできます。例:where CONVERT(DATE、MyDate)BETWEEN '2017-09-01' and '2017-09-30'このアプローチは、時間を作成しますDateTimeの要素は関係ありません
Pete

1
日付から3ミリ秒を引かないようにしてください。これらの3ミリ秒の項目は失われます。そして、あなたもしたくない日時日付それはインデックスは役に立たないレンダリングされますよう、。標準を使用します。また、ロケールに依存しているため、必ず使用してください。サーバーの設定によっては誤って解釈されます。CONVERTWHERE OrderDate >= '20160601' AND OrderDate < '20160701'yyyymmddyyyy-mm-ddmdy, dmy, ymd, ydm, myd, and dym
Ian Boyd

254

はい。ただし、日付を間で使用する場合は注意してください。

BETWEEN '20090101' AND '20090131'

実際には午前12時と解釈されます。

BETWEEN '20090101 00:00:00' AND '20090131 00:00:00'

そのため、1月31日の間に発生したすべてのことを逃します。この場合、以下を使用する必要があります。

myDate >= '20090101 00:00:00' AND myDate < '20090201 00:00:00'  --CORRECT!

または

BETWEEN '20090101 00:00:00' AND '20090131 23:59:59' --WRONG! (see update!)

更新:日付が遅くても、その日の最後の秒の間にレコードを作成することは完全に可能です20090101 23:59:59.997!!

このため、このBETWEEN (firstday) AND (lastday 23:59:59)アプローチは推奨されません。

myDate >= (firstday) AND myDate < (Lastday+1)代わりにアプローチを使用してください。

この問題に関する良い記事はこちら


1
文字列に関する同様の問題はWHERE col BETWEEN 'a' AND 'z'、たとえばz行のほとんどを除外します。
マーティン・スミス

8
この点はもちろん正しいです。日付時刻を操作している場合でも、驚くことではありません。それがBETWEEN 5 AND 10含まれていないことを指摘することに類似しています10.2...
Andrzej Doyle

4
CASTINGのdatetimeようDATEに動作します:CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'
2014年

2
@craig、それは本当です。SQL2008以降を使用している限り、これは日付データ型が導入されたときです。また、その構文はすべての行の値を変換するため、そのフィールドでインデックスを使用することはできません(それが問題である場合)。
BradC 2014年

It is entirely possible to have records created within that last second of the day, with a datetime as late as 01/01/2009 23:59:59.997<-使用することができなかった、AND '01/31/2009 23:59:59.99999999'または9がいくつも必要
wal

16

SQL Server 2008の実例。

ソースデータ:

ID    Start
1     2010-04-30 00:00:01.000
2     2010-04-02 00:00:00.000
3     2010-05-01 00:00:00.000
4     2010-07-31 00:00:00.000

クエリ:

SELECT
    *
FROM
    tbl
WHERE
    Start BETWEEN '2010-04-01 00:00:00' AND '2010-05-01 00:00:00'

結果:

ID    Start
1     2010-04-30 00:00:01.000
2     2010-04-02 00:00:00.000

代替テキスト


正直言って、あなたの答えはわかりませんでした。たぶん、あなたがスクリーンショットを投稿した場合、私のインターネットプロバイダーがあなたのスクリーンショットを隠しているかもしれません。
anar khalilov 2014年

2
行がID = 3除外されているのはなぜですか?そのStart値はBETWEEN上限値に等しくBETWEEN、包括的な範囲であり、排他的な上限範囲ではありません。

結果でより良い答え。
Sam

13

これにヒットし、コードに1日追加することを実際に処理したくない場合は、DBに任せてください。

myDate >= '20090101 00:00:00' AND myDate < DATEADD(day,1,'20090101 00:00:00')

時間部分を含める場合は、午前0時を参照していることを確認してください。それ以外の場合は、単に時間を省略できます。

myDate >= '20090101' AND myDate < DATEADD(day,1,'20090101')

心配する必要はありません。


12

BETWEEN(Transact-SQL)

テストするa(n)(両端を含む)範囲を指定します。

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

議論

test_expression

begin_expressionとend_expressionで定義された範囲でテストする式です。test_expressionは、begin_expressionとend_expressionの両方と同じデータ型である必要があります。

NOT

述語の結果が否定されることを指定します。

begin_expression

有効な式です。begin_expressionは、test_expressionおよびend_expressionの両方と同じデータ型である必要があります。

end_expression

有効な式です。end_expressionは、test_expressionとbegin_expressionの両方と同じデータ型である必要があります。

AND

test_expressionがbegin_expressionおよびend_expressionで示される範囲内にあることを示すプレースホルダーとして機能します。

備考

排他的な範囲を指定するには、大なり演算子(>)および小なり演算子(<)を使用します。BETWEENまたはNOT BETWEEN述部への入力がNULLの場合、結果はUNKNOWNになります。

結果値

BETWEENは、test_expressionの値がbegin_expressionの値以上で、end_expressionの値以下の場合にTRUEを返します。

NOT BETWEENは、test_expressionの値がbegin_expressionの値より小さいか、end_expressionの値より大きい場合にTRUEを返します。


3

列のデータ型が日時の場合、次のようにして日時から時間を削除し、日付範囲のみを比較できます。

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)

これは、終了日に+1を追加するよりも効果的です。私はAndrew Mortonに同意します-それが検索可能でない場合、列のデータ型を変更するか、事前に計算された日付のみを含む2番目の列を追加すると、パフォーマンスが向上する可能性があります。
アルノピーターズ

0

境界も含まれます。

declare @startDate date = cast('15-NOV-2016' as date) 
declare @endDate date = cast('30-NOV-2016' as date)
create table #test (c1 date)
insert into #test values(cast('15-NOV-2016' as date))
insert into #test values(cast('20-NOV-2016' as date))
insert into #test values(cast('30-NOV-2016' as date))
select * from #test where c1 between @startDate and @endDate
drop table #test
RESULT    c1
2016-11-15
2016-11-20
2016-11-30


declare @r1 int  = 10
declare @r2 int  = 15
create table #test1 (c1 int)
insert into #test1 values(10)
insert into #test1 values(15)
insert into #test1 values(11)
select * from #test1 where c1 between @r1 and @r2
drop table #test1
RESULT c1
10
11
15

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.