なぜSQLのBETWEENはハーフオープンではなく包括的ですか?


45

セミオープン(またはハーフオープン、ハーフクローズハーフバウンド)間隔([a,b)x間隔iffに属するa <= x < b)は、多くの便利なプロパティがあるため、プログラミングではかなり一般的です。

誰もがSQL BETWEENが閉じた間隔([a,b])を使用する理由を説明する根拠を提供できますか?これは特にです。日付に不便。なぜBETWEENこんなふうに振る舞うのでしょうか?


私は興味があります、彼らはどんな便利な特性を持っていますか?
phant0m

2
包括的ではない場合、範囲AからDのすべての姓を簡単に照会できますか?またはWからZの名前は?1から10までの数字では0 <n <11を検索できますが、文字の場合はASCII数字を使用する必要がありますか またはユニコード番号?さらに、インデックスを使用すると、データを簡単に開始できます。
jqa

2
私はあなたの欲求不満を理解しています、(StartDate> = '2010-01-01'およびStartDate <'2011-01-01')、うまく機能します。 2010-12-31 23:59:59 ')、かさばる人と12月の日数を知る必要がある人
トッド

1
@ phant0m [a、b)U [c、d)== [a、d)。[a:int、b:int)には正確にba要素が含まれています。トッドのコメントは、彼らが日付に対して特にうまく機能する方法を示しています(私はそれらが最も恋しいです)。基本的に、コーディングの際、セミオープン間隔はよりシンプルで使いやすく、堅牢になる傾向があります。
アレックス

最良の答えは、最初にSQLに対してBETWEENを指定した人々の客観的な決定文書を参照し、選択された主観的な答えではなく、なぜと答えるべきでした。
トッド14年

回答:


48

インクルーシブBETWEENは、セミオープンの間隔よりも直感的です(そして、明らかに、SQLデザイナーもそうでした)。たとえば、「1から10までの数字を選んでください」と言うと、ほとんどの人は1から10までの数字を含めます。SQLは、プログラマではない人が簡単なクエリを作成するために使用することがあり、セミオープンセマンティクスはそれらをはるかに混乱させます。


9
あなたの例は整数に焦点を合わせており、10進数やその他の区切られた量(日付など)については、間の用語があいまいです。2012年から2013年の間にXを実行したという場合、2013年(または具体的には2013-01-01日)は含まれません。
トッド

4
@Toddこれらの用語の使用法はあいまいです。そのため、数学者、科学者、および経験豊富なプログラマーは、自分の意図を「半開」などとして文書化します。Oleskiの答えのポイントは、SQLはもともとプログラマーではなくエンドユーザーを対象としていたということです(本当に!)。どうやらSQLデザイナーは、その対象者にとって最適だと思った定義を突き止めたようです。しかし、質問の著者が示唆しているように、時間の範囲などの範囲を操作する場合は、ほぼ常にハーフオープンの方が適しています。
バジルブルク14年

「包括的であることがより直感的だと思う」は主観的です。「SQLは、非プログラマーが簡単なクエリを作成するために時々使用します」-非プログラマーも同様に仕様を確認する必要があります。
トッド14年


質問には、「1 から 10 までの数字選ぶ」という質問もよくあります(明確なあいまいさを避けるためです)。補足として。「1から10の間の数字を選んでください」と言います。ほとんどの人はおそらく1も10も選択しません。確かにそれは心理学の問題です。:)人々はまだ1と10を有効な選択肢として受け入れます(意味的に間違っているにもかかわらず)。しかし、それは1と10が有効であると仮定した文脈解釈の結果です。「13と24の間」と言うと、13と24が含まれているかどうかを尋ねられる可能性が高くなります。
幻滅

26

質問:なぜSQLのBETWEENは包括的ですか?

回答:SQL言語の設計者は、開発者がBETWEENの4つのバリアント(closed、semi-open-left、semi-open-right、またはopen )彼らは好むだろう。

推奨事項:SQL標準が修正されるまで/修正されるまで、日付/時刻にBETWEENを使用しないでください。代わりに、BETWEEN範囲の開始境界と終了境界の独立した条件として、日付範囲比較をコーディングする習慣を身に付けます。これは少し冗長ですが、データベースオプティマイザーにとってわかりやすい(したがってバグが少ない)条件を記述し、最適な実行計画を決定し、使用するインデックスを作成できます。

たとえば、クエリが入力日の指定を受け入れ、その日付に該当するすべてのレコードを返す必要がある場合、次のようにコーディングします。

  • WHERE DATE_FIELD >= :dt AND DATE_FIELD < :dt+1

BETWEENを使用してロジックを記述しようとすると、パフォーマンスの問題やバグのあるコードが危険にさらされます。3つのよくある失敗:

1) WHERE DATE_FIELD BETWEEN :dt AND :dt+1

これはほぼ間違いなくバグです。ユーザーは特定の日付のレコードのみを表示することを期待していますが、ある日は翌日の午前12:00からのレコードを含むレポートで終わります。

2) WHERE TRUNC(DATE_FIELD) = :dt

正しい答えを与えますが、関数をDATE_FIELDに適用すると、ほとんどのインデックス付け/統計情報が役に立たなくなります(ただし、DBAは関数ベースのインデックスを日付フィールドに追加することで助けようとします-依然として工数とディスク容量を燃やし、IUDにオーバーヘッドを追加します)テーブルでの操作)

3) WHERE EVENT_DATE BETWEEN :dt AND :dt + 1-1/24/60/60

オラクルの第一人者であるTom Kyteは、この優劣(IMO)ソリューションを推奨しています。不完全な結果を与えるクエリでその「1-1 / 24/06/60」を見つけるために1日を過ごすまで、または誤ってTIMESTAMPフィールドでそれを使用するまで、うまく機能します。さらに、それは少し独自のものです。OracleのDATEデータ型(秒まで追跡)と互換性がありますが、異なるデータベース製品の日付/時刻の精度に調整する必要があります。

解決策:ANSI SQL委員会に対し、BETWEEN構文を変更してCLOSED / INCLUSIVEのデフォルトの代替の仕様をサポートすることにより、SQL言語仕様を強化するように要請します。このような何かがトリックを行います:

expr1 BETWEEN expr2 [ INCL [USIVE] | EXCL [USIVE]]およびexpr3 [ INCL [USIVE] | 排他的] ]

表現するのがどれだけ簡単になるかWHERE DATE_FIELD BETWEEN :dt INCLUSIVE AND :dt+1 EXCLUSIVE(または単にWHERE DATE_FIELD BETWEEN :dt AND :dt+1 EXCL)を考慮する

たぶんANSI SQL:2015?


この答えは賢明なアドバイスです。
バジルブルク14年

@KevinKirkPatrick-すばらしい回答です!また、元の理由の客観的な証拠として決定文書を見つけることをお勧めします。
トッド14年

3
個人的exp1 BETWEEN exp2 AND exp3 AND exp1 != exp3には、between演算子を保持する方法が気に入っているので、範囲付きの述語であり、不等号の述語はそれが半開であることを保証します。
センチネル

@Sentinel、ニース!早すぎる変換を宣言するつもりはありませんが、次の日付範囲条件をコーディングするときのために、このバリアントを必ず念頭に置いておきます。最初の赤面では、exp1> = exp2 AND exp1 <exp3よりも大きな言語的魅力があります。そして明らかにBETWEENの問題も同様にうまく解決します。オプティマイザーが一方のバリエーションを他方に対してより大きな「理解」を示すかどうかに興味があります。(率直に言って、私はかなり違ったそれらを扱うオプティマイザに失望するだろうが)確かに、それはあなたが同様にその点では良い結果をもたらすことがもっともらしく思える
KevinKirkpatrick

@KevinKirkpatrick違いがあるかどうかを確認するためにプロファイルを作成したことはありません。もしあれば、私も失望します。
センチネル

8

包括的(a <= x <= b)と排他的(a < x < b)の両方はほぼ同じように一般的であるため、標準を作成するときはどちらかを選択するだけでした。通常、一般的な英語の「間」は包括的であり、SQLステートメントは英語の文と同様に読むことを意図しているため、包括的が賢明な選択でした。


4
実際、Half-Openを省略したため、英語での使用はさらに複雑になります。ブレークまで行くと、00.000:00:私たちは、あなたが13の時点でバッククラス/仕事で期待されているという点で、我々は平均ハーフオープン「昼食は正午と午後1時間にある」と言うときは含まないの最初の瞬間1時です。a <= x < bハーフオープンです。
バジルブルク14年

1
@BasilBourque:これは無限の精度が原因である可能性があり-例えばランチ正午と12の間にある:59:99.9999999999999 ....
ブレンダン・

@ブレンダンはい、あなたは私の主張を述べています。無限(またはあいまいな)精度は、半開アプローチを使用して期間を定義することで処理される問題の1つです。ここでのポイントは、英語の会話では、オープンとクローズ(この回答で述べたように)、および半オープンの範囲をあまり考えずに直感的に処理することです。各アプローチには目的があります。そのため、BETWEENのSQL定義が最適とは言えません。理想的には、SQLはKevinKirkpatrick提案に従います。
バジルブルク14年

2
SQLは英語に似ていると想定されており、包括的および排他的は同様に一般的かもしれませんが、アナリストおよびプログラマー向けの照会言語です。プログラマーとして、間違って定義されていると思いますが、それは実際には問題ではなく、とにかく「BETWEEN」の使用を避けます。大したことではありません。
トッド14年

5

オペレータが呼び出されていない∩[a,b)、それが呼ばれていますBETWEEN、それはそれらのことをその意味論のための適切なかなりですので、英語のフレーズ数学的な述語のものより「間にある」「セミオープン区間です」。


整数セットの英語アプリケーションだけでなく、すべてのアプリケーションを考慮する必要があります。「1と10の間」、「正午と午後1時の間」、「1.0と5.0の間」(グラム)。「5.50〜10.30の間」(ドル)。連続量は論理的に(英語で)排他的であると見なされます。
トッド14年

1
問題は、BETWEENオペレーター英語のフレーズ「is between」のセマンティクスを使用しないことです。英語で「between」は、物事を分離する時間、空間、または間隔です(つまり、排他的です)。ゴールをキックしようとすると、ボールはポスト間を行き来して得点しなければなりません。あなたがそれらの間を通過することに失敗した投稿をヒットした場合-あなたのためのスコアはありません。
幻滅

1
@CraigYoungは、受け入れられた答えが示唆するように(そして同意します)、「私が「1から10の間の数字を選んでください」と言えば、ほとんどの人は数字1と10を含みます。では、空間ドメイン私はあなたと同意するが、数字のために、私はそれは違うと思います。以下のためのより良い英語&使用方法ここよりもかかわらず!
AakashM

@AakashM私のポイントは、プログラミングのセマンティクスを正当化するために、単語「between」の辞書定義によって単純に偽である英語について主張したということです。「1から10の間」というフレーズの一般的な理解があるという事実は、「間」の意味とはあまり関係がなく、10進数システムで保持される1と10の位置に関係があります。人間の脳の「自動修正」は、「2から9」を意味するのはばかげているように見えるため、この場合「間」が終点を除外することを無視します。「13と24の間」で同じことを試してください。または「0と11の間」です。
幻滅

あなたと私の間では、自然言語についてのカテゴリー的な主張は通常安全ではありません。
AakashM
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.