web-dev-qa-db-ja.com

Oracle date "Between"クエリ

Oracleデータベースを使用しています。 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'

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

前もって感謝します。

51
Gnaniyar Zubair

出力から判断すると、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時に設定します。 BETWEENfrom側では問題ありませんが、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')
82
APC

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

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');
22
Chad Birch

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

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

例えば

DESCRIBE mytable

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

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

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

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

したがって、start_dateにインデックスがあり、これがTIMESTAMPデータ型であり、オプティマイザにそれを考慮させると仮定すると、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が15-JAN-10 00:00:00:00000から17-JAN-10 23:59:59:99999として表示されるため、タイムスタンプの時間コンポーネントに関係なく、2010年1月15日、16日、17日のすべての日付を含めます。

お役に立てば幸いです。

ダッツァー

3
Darren Atkinson

クエリ間の日付

SELECT *
    FROM emp
    WHERE HIREDATE between to_date (to_char(sysdate, 'yyyy') ||'/09/01', 'yyyy/mm/dd')
    AND to_date (to_char(sysdate, 'yyyy') + 1|| '/08/31', 'yyyy/mm/dd');
1
user3496353

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

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'))
1
Ajay