Re: Search between date ranges

From: <fitzjarrell_at_cox.net>
Date: Wed, 30 Jul 2008 05:47:29 -0700 (PDT)
Message-ID: <6998cdca-ba5b-41a7-90ad-0907f7669703@f63g2000hsf.googlegroups.com>


Comments embedded.
On Jul 30, 5:23 am, Chris <christopherc..._at_hotmail.com> wrote:
> Hi Guys,
>
> I am trying to bild a cursor based on a select statement which returns
> values between a certain date range.  I have read that it is best
> avoiding the BETWEEN function of SQL.

Where did you read that? It clearly is not true:

SQL> select ename, empno, hiredate
  2 from emp
  3 where hiredate between to_date('17-DEC-1980','DD-MON-YYYY') and to_date('17-NOV-1981','DD-MON-YYYY')
  4 /

ENAME EMPNO HIREDATE

---------- ---------- ---------
SMYTHE           7369 17-DEC-80
ALLEN            7499 20-FEB-81
WARD             7521 22-FEB-81
JONES            7566 02-APR-81
MARTIN           7654 28-SEP-81
BLAKE            7698 01-MAY-81
CLARK            7782 09-JUN-81
KING             7839 17-NOV-81
TURNER           7844 08-SEP-81

9 rows selected.

Execution Plan



Plan hash value: 2872589290
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)|
Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     9 |   162 |     3   (0)|
00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMP  |     9 |   162 |     3   (0)|
00:00:01 |

Predicate Information (identified by operation id):


   1 - filter("HIREDATE"<=TO_DATE('1981-11-17 00:00:00', 'yyyy-mm-dd

              hh24:mi:ss') AND "HIREDATE">=TO_DATE('1980-12-17 00:00:00', 'yyyy-mm-dd

              hh24:mi:ss'))

Statistics


          0  recursive calls
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
        490  bytes sent via SQL*Net to client
        246  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          9  rows processed

SQL>

SQL>
SQL> select ename, empno, hiredate
  2 from emp
  3 where hiredate >= to_date('17-DEC-1980','DD-MON-YYYY') and hiredate <= to_date('17-NOV-1981','DD-MON-YYYY')   4
SQL> / ENAME EMPNO HIREDATE
---------- ---------- ---------
SMYTHE           7369 17-DEC-80
ALLEN            7499 20-FEB-81
WARD             7521 22-FEB-81
JONES            7566 02-APR-81
MARTIN           7654 28-SEP-81
BLAKE            7698 01-MAY-81
CLARK            7782 09-JUN-81
KING             7839 17-NOV-81
TURNER           7844 08-SEP-81

9 rows selected.

Execution Plan



Plan hash value: 2872589290
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)|
Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     9 |   162 |     3   (0)|
00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMP  |     9 |   162 |     3   (0)|
00:00:01 |

Predicate Information (identified by operation id):


   1 - filter("HIREDATE"<=TO_DATE('1981-11-17 00:00:00', 'yyyy-mm-dd

              hh24:mi:ss') AND "HIREDATE">=TO_DATE('1980-12-17 00:00:00', 'yyyy-mm-dd

              hh24:mi:ss'))

Statistics


          0  recursive calls
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
        490  bytes sent via SQL*Net to client
        246  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          9  rows processed

SQL> Note both queries produce the same execution plan, with the same filter, as BETWEEN is silently rewritten to the form you've implemented.

>
> Instead I hav written :
>
> AND ol.actual_shipment_date >= p_date_from
> AND ol.actual_shipment_date <= (p_date_to)
>

Which, as shown above, Oracle does for you.

> If I have the p_date_from parameter set to 01-JAN-08 and the p_date_to
> parameter set to 10-JAN-08 it will only return dates from 01-JAN to 09-
> JAN (not the 10th)
>
> To overcome this I have written :
>
> AND ol.actual_shipment_date >= p_date_from
> AND ol.actual_shipment_date <= (p_date_to +1)
>
> This seems a very crude way of doing it and was wondering if there is
> an easier way?
>
> Thanks in advance,
> Chris

A solution has already been presented, but I will repeat it here:

AND trunc(ol.actual_shipment_date) >= p_date_from AND trunc(ol.actual_shipment_date) <= p_date_to

Of course it appears you're relying upon a default date mask, which can backfire on you without warning since the default used in one installation may not be the same as the chosen 'default' for another:

SQL> select empno, ename, hiredate
  2 from emp
  3 where hiredate <= '17-NOV-81'
  4 /

     EMPNO ENAME HIREDATE

---------- ---------- ---------
      7369 SMYTHE     17-DEC-80
      7499 ALLEN      20-FEB-81
      7521 WARD       22-FEB-81
      7566 JONES      02-APR-81
      7654 MARTIN     28-SEP-81
      7698 BLAKE      01-MAY-81
      7782 CLARK      09-JUN-81
      7839 KING       17-NOV-81
      7844 TURNER     08-SEP-81

9 rows selected.

SQL>
SQL> alter session set nls_date_format = 'MON-DD-YYYY';

Session altered.

SQL>
SQL> select empno, ename, hiredate
  2 from emp
  3 where hiredate <= '17-NOV-81'
  4 /
where hiredate <= '17-NOV-81'

                  *

ERROR at line 3:
ORA-01843: not a valid month

SQL> As a better solution you should use either the to_date function or the to_char function; I would opt for the latter in this case:

AND to_char(ol.actual_shipment_date, 'DD-MON-RR') BETWEEN p_date_from and p_date_to

This would return the values you expect, and eliminates your kludge.

David Fitzjarrell Received on Wed Jul 30 2008 - 07:47:29 CDT

Original text of this message