55

私はオラクルデータベースを使用しています。1 つのクエリを実行して、2 つの日付間のデータを確認したいと考えています。

NAME               START_DATE    
-------------    ------------- 
Small Widget       15-JAN-10 04.25.32.000000 PM      
Product 1          17-JAN-10 04.31.32.000000 PM  



select * from <TABLENAME> where start_date  
BETWEEN '15-JAN-10' AND '17-JAN-10'

しかし、上記のクエリから結果が得られません。「いいね」と「%」を使わないといけないと思います。しかし、私はそれらをどこで使用するのかわかりません。これにいくつかのライトを投げてください。

前もって感謝します。

4

5 に答える 5

89

出力から判断すると、START_DATE をタイムスタンプとして定義したようです。通常の日付であれば、Oracle は暗黙的な変換を処理できます。しかし、そうではないので、これらの文字列を明示的に日付にキャストする必要があります。

SQL> alter session set nls_date_format = 'dd-mon-yyyy hh24:mi:ss'
  2  /

Session altered.

SQL>
SQL> select * from t23
  2  where start_date between '15-JAN-10' and '17-JAN-10'
  3  /

no rows selected

SQL> select * from t23
  2  where start_date between to_date('15-JAN-10') and to_date('17-JAN-10')
  3  /

WIDGET                          START_DATE
------------------------------  ----------------------
Small Widget                    15-JAN-10 04.25.32.000    

SQL> 

しかし、まだ 1 行しか取得できません。これは、START_DATE に時間要素があるためです。時間コンポーネントを指定しない場合、Oracle はデフォルトで午前 0 時に設定します。これはfrom側では問題ありBETWEENませんが、until側では問題ありません。

SQL> select * from t23
  2  where start_date between to_date('15-JAN-10') 
  3                       and to_date('17-JAN-10 23:59:59')
  4  /

WIDGET                          START_DATE
------------------------------  ----------------------
Small Widget                    15-JAN-10 04.25.32.000
Product 1                       17-JAN-10 04.31.32.000

SQL>

編集

時間コンポーネントを渡すことができない場合は、いくつかの選択肢があります。1 つは、条件から時間要素を削除するように WHERE 句を変更することです。

where trunc(start_date) between to_date('15-JAN-10') 
                            and to_date('17-JAN-10')

これは、START_DATE の B ツリー インデックスを無効にするため、パフォーマンスに影響を与える可能性があります。代わりに、関数ベースのインデックスを作成する必要があります。

または、コードの日付に時間要素を追加することもできます。

where start_date between to_date('15-JAN-10') 
                     and to_date('17-JAN-10') + (86399/86400) 

これらの問題のため、多くの人は次のbetweenように日付の境界をチェックして の使用を避けることを好みます。

where start_date >= to_date('15-JAN-10') 
and start_date < to_date('18-JAN-10')
于 2010-03-03T07:02:40.357 に答える
23

これらを文字列ではなく実際の日付に変換する必要があります。これを試してください:

SELECT *
FROM <TABLENAME>
WHERE start_date BETWEEN TO_DATE('2010-01-15','YYYY-MM-DD') AND TO_DATE('2010-01-17', 'YYYY-MM-DD');

指定された形式を処理するように編集:

SELECT *
FROM <TABLENAME>
WHERE start_date BETWEEN TO_DATE('15-JAN-10','DD-MON-YY') AND TO_DATE('17-JAN-10','DD-MON-YY');
于 2010-03-03T06:45:51.780 に答える
3

APCが正しく指摘しているように、start_date列はTIMESTAMPのように見えますが、TIMESTAMP WITHLOCALTIMEZONEまたはTIMESTAMPWITHTIMEZONEデータ型の場合もあります。データベースサーバーが自分とは異なるタイムゾーンにある場合、これらはデータに対して実行しているクエリに影響を与える可能性があります。ただし、これを単純に保ち、サーバーと同じタイムゾーンにいると仮定しましょう。まず、自信を持たせるために、start_dateがTIMESTAMPデータ型であることを確認してください。

SQLPlus DESCRIBEコマンド(またはIDEの同等のコマンド)を使用して、この列がTIMESTAMPデータ型であることを確認します。

例えば

mytableを説明する

報告する必要があります:

Name        Null? Type
----------- ----- ------------
NAME              VARHAR2(20) 
START_DATE        TIMESTAMP

Type = TIMESTAMPとして報告されている場合は、引数(または画像)を必要としない最も単純なTO_TIMESTAMP日付変換を使用して、日付範囲を照会できます。

TO_TIMESTAMPを使用して、START_DATE列のすべての索引がオプティマイザーによって考慮されるようにします。APCの回答では、この列に関数ベースのインデックスが作成されている可能性があり、SQL述語に影響を与える可能性があることも示されていますが、このクエリではコメントできません。テーブルに適用されているインデックスを確認する方法を知りたい場合は、別の質問を投稿してください。個別に回答できます。

したがって、timeSTAMPデータ型であるstart_dateにインデックスがあり、オプティマイザーにそれを考慮させたいとすると、SQLは次のようになります。

select * from mytable where start_date between to_timestamp('15-JAN-10') AND to_timestamp('17-JAN-10')+.9999999

+.999999999は非常に近いですが、完全に1ではないため、17-JAN-10の変換は、その日の深夜に可能な限り近くなります。したがって、クエリは両方の行を返します。

データベースには、BETWEENが2010年1月15日00:00:00:00000から2010年1月17日23:59:59:99999までと表示されるため、2010年1月15日、16日、17日のすべての日付がいつでも含まれます。タイムスタンプのコンポーネント。

お役に立てば幸いです。

ダザー

于 2010-03-03T11:39:39.347 に答える
1

次のクエリも使用できます。

select * 
  from t23
 where trunc(start_date) between trunc(to_date('01/15/2010','mm/dd/yyyy')) and trunc(to_date('01/17/2010','mm/dd/yyyy'))
于 2015-03-30T12:14:13.240 に答える